home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / hplip / base / device.py < prev    next >
Text File  |  2009-10-09  |  87KB  |  2,491 lines

  1. # -*- coding: utf-8 -*-
  2. #
  3. # (c) Copyright 2003-2009 Hewlett-Packard Development Company, L.P.
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18. #
  19. # Author: Don Welch
  20. #
  21.  
  22. # Std Lib
  23. import socket
  24. import re
  25. import gzip
  26. import os.path
  27. import time
  28. import urllib # TODO: Replace with urllib2 (urllib is deprecated in Python 3.0)
  29. import StringIO
  30. import httplib
  31. import struct
  32.  
  33. # Local
  34. from g import *
  35. from codes import *
  36. import utils
  37. import status
  38. import pml
  39. from prnt import pcl, ldl, cups
  40. import models, mdns, slp
  41. from strings import StringTable
  42.  
  43.  
  44. try:
  45.     import hpmudext
  46. except ImportError:
  47.     if not os.getenv("HPLIP_BUILD"):
  48.         log.error("HPMUDEXT could not be loaded. Please check HPLIP installation.")
  49.         sys.exit(1)
  50. else:
  51.     # Workaround for build machine
  52.     try:
  53.         MAX_BUFFER = hpmudext.HPMUD_BUFFER_SIZE
  54.     except AttributeError:
  55.         MAX_BUFFER = 8192
  56.  
  57. dbus_avail = False
  58. dbus_disabled = False
  59. try:
  60.     import dbus
  61.     from dbus import lowlevel, SessionBus
  62.     dbus_avail = True
  63. except ImportError:
  64.     log.warn("python-dbus not installed.")
  65.  
  66. import warnings
  67. # Ignore: .../dbus/connection.py:242: DeprecationWarning: object.__init__() takes no parameters
  68. # (occurring on Python 2.6/dBus 0.83/Ubuntu 9.04)
  69. warnings.simplefilter("ignore", DeprecationWarning)
  70.  
  71.  
  72. DEFAULT_PROBE_BUS = ['usb', 'par', 'cups']
  73. VALID_BUSES = ('par', 'net', 'cups', 'usb') #, 'bt', 'fw')
  74. VALID_BUSES_WO_CUPS = ('par', 'net', 'usb')
  75. DEFAULT_FILTER = None
  76. VALID_FILTERS = ('print', 'scan', 'fax', 'pcard', 'copy')
  77. DEFAULT_BE_FILTER = ('hp',)
  78.  
  79. pat_deviceuri = re.compile(r"""(.*):/(.*?)/(\S*?)\?(?:serial=(\S*)|device=(\S*)|ip=(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}[^&]*)|zc=(\S+))(?:&port=(\d))?""", re.IGNORECASE)
  80. http_pat_url = re.compile(r"""/(.*?)/(\S*?)\?(?:serial=(\S*)|device=(\S*))&loc=(\S*)""", re.IGNORECASE)
  81. direct_pat = re.compile(r'direct (.*?) "(.*?)" "(.*?)" "(.*?)"', re.IGNORECASE)
  82.  
  83. # Pattern to check for ; at end of CTR fields
  84. # Note: If ; not present, CTR value is invalid
  85. pat_dynamic_ctr = re.compile(r"""CTR:\d*\s.*;""", re.IGNORECASE)
  86.  
  87. # Cache for model data
  88. model_dat = models.ModelData()
  89.  
  90. ip_pat = re.compile(r"""\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b""", re.IGNORECASE)
  91. dev_pat = re.compile(r"""/dev/.+""", re.IGNORECASE)
  92. usb_pat = re.compile(r"""(\d+):(\d+)""", re.IGNORECASE)
  93.  
  94. #
  95. # Event Wrapper Class for pipe IPC
  96. #
  97.  
  98. class Event(object):
  99.     def __init__(self, device_uri, printer_name, event_code,
  100.                  username=prop.username, job_id=0, title='',
  101.                  timedate=0):
  102.  
  103.         self.device_uri = unicode(utils.xrstrip(device_uri, '\x00'))[:64].encode('utf-8')
  104.         self.printer_name = unicode(utils.xrstrip(printer_name, '\x00'))[:64].encode('utf-8')
  105.         self.event_code = int(event_code)
  106.         self.username = unicode(utils.xrstrip(username, '\x00'))[:32].encode('utf-8')
  107.         self.job_id = int(job_id)
  108.         self.title = unicode(utils.xrstrip(title, '\x00'))[:64].encode('utf-8')
  109.  
  110.         if timedate:
  111.             self.timedate = float(timedate)
  112.         else:
  113.             self.timedate = time.time()
  114.  
  115.         self.pipe_fmt = "64s64sI32sI64sf"
  116.         self.dbus_fmt = "ssisisd"
  117.  
  118.  
  119.     def debug(self):
  120.         log.debug("    device_uri=%s" % self.device_uri)
  121.         log.debug("    printer_name=%s" % self.printer_name)
  122.         log.debug("    event_code=%d" % self.event_code)
  123.         log.debug("    username=%s" % self.username)
  124.         log.debug("    job_id=%d" % self.job_id)
  125.         log.debug("    title=%s" % self.title)
  126.         log.debug("    timedate=%s" % self.timedate)
  127.  
  128.  
  129.     def pack_for_pipe(self):
  130.         return struct.pack(self.pipe_fmt, self.device_uri, self.printer_name,
  131.                 self.event_code, self.username, self.job_id, self.title,
  132.                 self.timedate)
  133.  
  134.  
  135.     def send_via_pipe(self, fd, recipient='hpssd'):
  136.         if fd is not None:
  137.             log.debug("Sending event %d to %s (via pipe %d)..." % (self.event_code, recipient, fd))
  138.             try:
  139.                 os.write(fd, self.pack_for_pipe())
  140.                 return True
  141.             except OSError:
  142.                 log.debug("Failed.")
  143.                 return False
  144.  
  145.  
  146.     def send_via_dbus(self, session_bus, interface='com.hplip.StatusService'):
  147.         if session_bus is not None and dbus_avail:
  148.             log.debug("Sending event %d to %s (via dbus)..." % (self.event_code, interface))
  149.             msg = lowlevel.SignalMessage('/', interface, 'Event')
  150.             msg.append(signature=self.dbus_fmt, *self.as_tuple())
  151.             session_bus.send_message(msg)
  152.  
  153.  
  154.     def copy(self):
  155.         return Event(*self.as_tuple())
  156.  
  157.  
  158.     def __str__(self):
  159.         return "<Event('%s', '%s', %d, '%s', %d, '%s', %f)>" % self.as_tuple()
  160.  
  161.  
  162.     def as_tuple(self):
  163.         return (self.device_uri, self.printer_name, self.event_code,
  164.              self.username, self.job_id, self.title, self.timedate)
  165.  
  166.  
  167. class FaxEvent(Event):
  168.     def __init__(self, temp_file, event):
  169.         Event.__init__(self, *event.as_tuple())
  170.         self.temp_file = temp_file
  171.         self.pipe_fmt = "64s64sI32sI64sfs"
  172.         self.dbus_fmt = "ssisisfs"
  173.  
  174.  
  175.     def debug(self):
  176.         log.debug("FAX:")
  177.         Event.debug(self)
  178.         log.debug("    temp_file=%s" % self.temp_file)
  179.  
  180.  
  181.     def __str__(self):
  182.         return "<FaxEvent('%s', '%s', %d, '%s', %d, '%s', %f, '%s')>" % self.as_tuple()
  183.  
  184.  
  185.     def as_tuple(self):
  186.         return (self.device_uri, self.printer_name, self.event_code,
  187.              self.username, self.job_id, self.title, self.timedate,
  188.              self.temp_file)
  189.  
  190.  
  191.  
  192. class DeviceIOEvent(Event):
  193.     def __init__(self, bytes_written, event):
  194.         Event.__init__(self, *event.as_tuple())
  195.         self.bytes_written = bytes_written
  196.         self.pipe_fmt = "64s64sI32sI64sfI"
  197.         self.dbus_fmt = "ssisisfi"
  198.  
  199.  
  200.     def debug(self):
  201.         log.debug("DEVIO:")
  202.         Event.debug(self)
  203.         log.debug("    bytes_written=%d" % self.bytes_written)
  204.  
  205.  
  206.     def __str__(self):
  207.         return "<DeviceIOEvent('%s', '%s', %d, '%s', %d, '%s', %f, '%d')>" % self.as_tuple()
  208.  
  209.  
  210.     def as_tuple(self):
  211.         return (self.device_uri, self.printer_name, self.event_code,
  212.              self.username, self.job_id, self.title, self.timedate,
  213.              self.bytes_written)
  214.  
  215.  
  216. #
  217. # DBus Support
  218. #
  219.  
  220. def init_dbus(dbus_loop=None):
  221.     global dbus_avail
  222.     service = None
  223.     session_bus = None
  224.  
  225.     if not prop.gui_build:
  226.         dbus_avail = False
  227.         return dbus_avail, None,  None
  228.  
  229.     if dbus_avail and not dbus_disabled:
  230.         if os.getuid() == 0:
  231.             log.debug("Not starting dbus: running as root.")
  232.             dbus_avail = False
  233.             return dbus_avail, None,  None
  234.  
  235.         try:
  236.             if dbus_loop is None:
  237.                 session_bus = dbus.SessionBus()
  238.             else:
  239.                 session_bus = dbus.SessionBus(dbus_loop)
  240.         except dbus.exceptions.DBusException, e:
  241.             if os.getuid() != 0:
  242.                 log.error("Unable to connect to dbus session bus.")
  243.             else:
  244.                 log.debug("Unable to connect to dbus session bus (running as root?)")
  245.  
  246.             dbus_avail = False
  247.             return dbus_avail, None,  None
  248.  
  249.         try:
  250.             log.debug("Connecting to com.hplip.StatusService (try #1)...")
  251.             service = session_bus.get_object('com.hplip.StatusService', "/com/hplip/StatusService")
  252.             dbus_avail = True
  253.         except dbus.exceptions.DBusException, e:
  254.             try:
  255.                 os.waitpid(-1, os.WNOHANG)
  256.             except OSError:
  257.                 pass
  258.  
  259.             path = utils.which('hp-systray')
  260.             if path:
  261.                 path = os.path.join(path, 'hp-systray')
  262.             else:
  263.                 path = os.path.join(prop.home_dir, 'systray.py')
  264.                 if not os.path.exists(path):
  265.                     log.warn("Unable to start hp-systray")
  266.                     return False, None,  None
  267.  
  268.             log.debug("Running hp-systray: %s --force-startup" % path)
  269.  
  270.             os.spawnlp(os.P_NOWAIT, path, 'hp-systray', '--force-startup')
  271.  
  272.             log.debug("Waiting for hp-systray to start...")
  273.             time.sleep(1)
  274.  
  275.             t = 2
  276.             while True:
  277.                 try:
  278.                     log.debug("Connecting to com.hplip.StatusService (try #%d)..." % t)
  279.                     service = session_bus.get_object('com.hplip.StatusService', "/com/hplip/StatusService")
  280.  
  281.                 except dbus.exceptions.DBusException, e:
  282.                     log.debug("Unable to connect to dbus. Is hp-systray running?")
  283.                     t += 1
  284.  
  285.                     if t > 5:
  286.                         log.warn("Unable to connect to dbus. Is hp-systray running?")
  287.                         return False, None,  None
  288.  
  289.                     time.sleep(1)
  290.  
  291.                 else:
  292.                     log.debug("Connected.")
  293.                     dbus_avail = True
  294.                     break
  295.  
  296.     return dbus_avail, service,  session_bus
  297.  
  298.  
  299. #
  300. # Make URI from parameter (bus ID, IP address, etc)
  301. #
  302.  
  303. def makeURI(param, port=1):
  304.     cups_uri, sane_uri, fax_uri = '', '', ''
  305.     found = False
  306.  
  307.     if dev_pat.search(param) is not None: # parallel
  308.         log.debug("Trying parallel with %s" % param)
  309.  
  310.         result_code, uri = hpmudext.make_par_uri(param)
  311.  
  312.         if result_code == hpmudext.HPMUD_R_OK and uri:
  313.             log.debug("Found: %s" % uri)
  314.             found = True
  315.             cups_uri = uri
  316.         else:
  317.             log.debug("Not found.")
  318.  
  319.     elif usb_pat.search(param) is not None: # USB
  320.         match_obj = usb_pat.search(param)
  321.         usb_bus_id = match_obj.group(1)
  322.         usb_dev_id = match_obj.group(2)
  323.  
  324.         log.debug("Trying USB with bus=%s dev=%s..." % (usb_bus_id, usb_dev_id))
  325.         result_code, uri = hpmudext.make_usb_uri(usb_bus_id, usb_dev_id)
  326.  
  327.         if result_code == ERROR_SUCCESS and uri:
  328.             log.debug("Found: %s" % uri)
  329.             found = True
  330.             cups_uri = uri
  331.         else:
  332.             log.debug("Not found.")
  333.  
  334.     elif ip_pat.search(param) is not None: # IPv4 dotted quad
  335.         log.debug("Trying IP address %s" % param)
  336.  
  337.         result_code, uri = hpmudext.make_net_uri(param, port)
  338.  
  339.         if result_code == hpmudext.HPMUD_R_OK and uri:
  340.             log.debug("Found: %s" % uri)
  341.             found = True
  342.             cups_uri = uri
  343.         else:
  344.             log.debug("Not found.")
  345.  
  346.     else: # Try Zeroconf hostname
  347.         log.debug("Trying ZC hostname %s" % param)
  348.  
  349.         result_code, uri = hpmudext.make_zc_uri(param, port)
  350.  
  351.         if result_code == hpmudext.HPMUD_R_OK and uri:
  352.             log.debug("Found: %s" % uri)
  353.             found = True
  354.             cups_uri = uri
  355.         else:
  356.             log.debug("Not found.")
  357.  
  358.     if not found:
  359.         log.debug("Trying serial number %s" % param)
  360.         devices = probeDevices(bus=['usb', 'par'])
  361.  
  362.         for d in devices:
  363.             log.debug(d)
  364.  
  365.             # usb has serial in URI...
  366.             try:
  367.                 back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
  368.                     parseDeviceURI(d)
  369.             except Error:
  370.                 continue
  371.  
  372.             if bus == 'par': # ...parallel does not. Must get Device ID to obtain it...
  373.                 mq = queryModelByURI(d)
  374.  
  375.                 result_code, device_id = \
  376.                     hpmudext.device_open(d, mq.get('io-mode', hpmudext.HPMUD_UNI_MODE))
  377.  
  378.                 if result_code == hpmudext.HPMUD_R_OK:
  379.                     result_code, data = hpmudext.get_device_id(device_id)
  380.                     serial = parseDeviceID(data).get('SN', '')
  381.                     hpmudext.close_device(device_id)
  382.  
  383.             if serial.lower() == param.lower():
  384.                 log.debug("Found: %s" % d)
  385.                 found = True
  386.                 cups_uri = d
  387.                 break
  388.             else:
  389.                 log.debug("Not found.")
  390.  
  391.     if found:
  392.         try:
  393.             mq = queryModelByURI(cups_uri)
  394.         except Error, e:
  395.             log.error("Error: %s" % e.msg)
  396.             cups_uri, sane_uri, fax_uri = '', '', ''
  397.         else:
  398.             if mq.get('support-type', SUPPORT_TYPE_NONE) > SUPPORT_TYPE_NONE:
  399.                 if mq.get('scan-type', 0):
  400.                     sane_uri = cups_uri.replace("hp:", "hpaio:")
  401.  
  402.                 if mq.get('fax-type', 0):
  403.                     fax_uri = cups_uri.replace("hp:", "hpfax:")
  404.  
  405.             else:
  406.                 cups_uri, sane_uri, fax_uri = '', '', ''
  407.  
  408.     else:
  409.         scan_uri, fax_uri = '', ''
  410.  
  411.     if cups_uri:
  412.         user_conf.set('last_used', 'device_uri', cups_uri)
  413.  
  414.     return cups_uri, sane_uri, fax_uri
  415.  
  416.  
  417. #
  418. # Model Queries
  419. #
  420.  
  421. def queryModelByModel(model):
  422.     model = models.normalizeModelName(model).lower()
  423.     return model_dat[model]
  424.  
  425.  
  426. def queryModelByURI(device_uri):
  427.     try:
  428.         back_end, is_hp, bus, model, \
  429.             serial, dev_file, host, zc, port = \
  430.             parseDeviceURI(device_uri)
  431.     except Error:
  432.         raise Error(ERROR_INVALID_DEVICE_URI)
  433.     else:
  434.         return queryModelByModel(model)
  435.  
  436.  
  437. #
  438. # Device Discovery
  439. #
  440.  
  441. def probeDevices(bus=DEFAULT_PROBE_BUS, timeout=10,
  442.                  ttl=4, filter=DEFAULT_FILTER,  search='', net_search='mdns',
  443.                  back_end_filter=('hp',)):
  444.  
  445.     num_devices, ret_devices = 0, {}
  446.  
  447.     if search:
  448.         try:
  449.             search_pat = re.compile(search, re.IGNORECASE)
  450.         except:
  451.             log.error("Invalid search pattern. Search uses standard regular expressions. For more info, see: http://www.amk.ca/python/howto/regex/")
  452.             search = ''
  453.  
  454.     for b in bus:
  455.         log.debug("Probing bus: %s" % b)
  456.         if b not in VALID_BUSES:
  457.             log.error("Invalid bus: %s" % b)
  458.             continue
  459.  
  460.         if b == 'net':
  461.             if net_search == 'slp':
  462.                 try:
  463.                     detected_devices = slp.detectNetworkDevices(ttl, timeout)
  464.                 except Error, socket.error:
  465.                     log.error("An error occured during network probe.")
  466.                     raise ERROR_INTERNAL
  467.             else:
  468.                 try:
  469.                     detected_devices = mdns.detectNetworkDevices(ttl, timeout)
  470.                 except Error, socket.error:
  471.                     log.error("An error occured during network probe.")
  472.                     raise ERROR_INTERNAL
  473.  
  474.             for ip in detected_devices:
  475.                 update_spinner()
  476.                 hn = detected_devices[ip].get('hn', '?UNKNOWN?')
  477.                 num_devices_on_jd = detected_devices[ip].get('num_devices', 0)
  478.                 num_ports_on_jd = detected_devices[ip].get('num_ports', 1)
  479.  
  480.                 if num_devices_on_jd > 0:
  481.                     for port in range(num_ports_on_jd):
  482.                         dev = detected_devices[ip].get('device%d' % (port+1), '0')
  483.  
  484.                         if dev is not None and dev != '0':
  485.                             device_id = parseDeviceID(dev)
  486.                             model = models.normalizeModelName(device_id.get('MDL', '?UNKNOWN?'))
  487.  
  488.                             if num_ports_on_jd == 1:
  489.                                 if net_search == 'slp':
  490.                                     device_uri = 'hp:/net/%s?ip=%s' % (model, ip)
  491.                                 else:
  492.                                     device_uri = 'hp:/net/%s?zc=%s' % (model, hn)
  493.                             else:
  494.                                 if net_search == 'slp':
  495.                                     device_uri = 'hp:/net/%s?ip=%s&port=%d' % (model, ip, (port + 1))
  496.                                 else:
  497.                                     device_uri = 'hp:/net/%s?zc=%s&port=%d' % (model, hn, (port + 1))
  498.  
  499.                             include = True
  500.                             mq = queryModelByModel(model)
  501.  
  502.                             if not mq:
  503.                                 log.debug("Not found.")
  504.                                 include = False
  505.  
  506.                             elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  507.                                 log.debug("Not supported.")
  508.                                 include = False
  509.  
  510.                             elif filter not in (None, 'print', 'print-type'):
  511.                                 include = __checkFilter(filter, mq)
  512.  
  513.                             if include:
  514.                                 ret_devices[device_uri] = (model, model, hn)
  515.  
  516.         elif b in ('usb', 'par'):
  517.             if b == 'par':
  518.                 bn = hpmudext.HPMUD_BUS_PARALLEL
  519.             else:
  520.                 bn = hpmudext.HPMUD_BUS_USB
  521.  
  522.             result_code, data = hpmudext.probe_devices(bn)
  523.  
  524.             if result_code == hpmudext.HPMUD_R_OK:
  525.                 for x in data.splitlines():
  526.                     m = direct_pat.match(x)
  527.  
  528.                     uri = m.group(1) or ''
  529.                     mdl = m.group(2) or ''
  530.                     desc = m.group(3) or ''
  531.                     devid = m.group(4) or ''
  532.  
  533.                     log.debug(uri)
  534.  
  535.                     try:
  536.                         back_end, is_hp, bb, model, serial, dev_file, host, zc, port = \
  537.                             parseDeviceURI(uri)
  538.                     except Error:
  539.                         continue
  540.  
  541.                     include = True
  542.  
  543.                     if mdl and uri and is_hp:
  544.                         mq = queryModelByModel(model)
  545.  
  546.                         if not mq:
  547.                             log.debug("Not found.")
  548.                             include = False
  549.  
  550.                         elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  551.                             log.debug("Not supported.")
  552.                             include = False
  553.  
  554.                         elif filter not in (None, 'print', 'print-type'):
  555.                             include = __checkFilter(filter, mq)
  556.  
  557.                         if include:
  558.                             ret_devices[uri] = (mdl, desc, devid) # model w/ _'s, mdl w/o
  559.  
  560.         elif b == 'cups':
  561.             cups_printers = cups.getPrinters()
  562.             x = len(cups_printers)
  563.  
  564.             for p in cups_printers:
  565.                 device_uri = p.device_uri
  566.                 log.debug("%s: %s" % (device_uri, p.name))
  567.  
  568.                 if device_uri != '':
  569.                     try:
  570.                         back_end, is_hp, bs, model, serial, dev_file, host, zc, port = \
  571.                             parseDeviceURI(device_uri)
  572.                     except Error:
  573.                         log.debug("Unrecognized URI: %s" % device_uri)
  574.                         continue
  575.  
  576.                     if not is_hp:
  577.                         continue
  578.  
  579.                     include = True
  580.                     mq = queryModelByModel(model)
  581.  
  582.                     if not mq:
  583.                         include = False
  584.                         log.debug("Not found.")
  585.  
  586.                     elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  587.                         log.debug("Not supported.")
  588.                         include = False
  589.  
  590.                     elif filter not in (None, 'print', 'print-type'):
  591.                         include = __checkFilter(filter, mq)
  592.  
  593.                     if include:
  594.                         ret_devices[device_uri] = (model, model, '')
  595.  
  596.     probed_devices = {}
  597.     for uri in ret_devices:
  598.         num_devices += 1
  599.         mdl, model, devid_or_hn = ret_devices[uri]
  600.  
  601.         include = True
  602.         if search:
  603.             match_obj = search_pat.search("%s %s %s %s" % (mdl, model, devid_or_hn, uri))
  604.  
  605.             if match_obj is None:
  606.                 log.debug("%s %s %s %s: Does not match search '%s'." % (mdl, model, devid_or_hn, uri, search))
  607.                 include = False
  608.  
  609.         if include:
  610.             probed_devices[uri] = ret_devices[uri]
  611.  
  612.     cleanup_spinner()
  613.     return probed_devices
  614.  
  615. #
  616. # CUPS Devices
  617. #
  618.  
  619. def getSupportedCUPSDevices(back_end_filter=['hp'], filter=DEFAULT_FILTER):
  620.     devices = {}
  621.     printers = cups.getPrinters()
  622.  
  623.     for p in printers:
  624.         try:
  625.             back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
  626.                 parseDeviceURI(p.device_uri)
  627.  
  628.         except Error:
  629.             continue
  630.  
  631.         if (back_end_filter == '*' or back_end in back_end_filter or \
  632.             ('hpaio' in back_end_filter and back_end == 'hp')) and \
  633.             model and is_hp:
  634.  
  635.             include = True
  636.             mq = queryModelByModel(model)
  637.  
  638.             if not mq:
  639.                 log.debug("Not found.")
  640.                 include = False
  641.  
  642.             elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  643.                 log.debug("Not supported.")
  644.                 include = False
  645.  
  646.             elif filter not in (None, 'print', 'print-type'):
  647.                 include = __checkFilter(filter, mq)
  648.  
  649.             if include:
  650.                 if 'hpaio' in back_end_filter:
  651.                     d = p.device_uri.replace('hp:', 'hpaio:')
  652.                 else:
  653.                     d = p.device_uri
  654.  
  655.                 try:
  656.                     devices[d]
  657.                 except KeyError:
  658.                     devices[d] = [p.name]
  659.                 else:
  660.                     devices[d].append(p.name)
  661.  
  662.     return devices # { 'device_uri' : [ CUPS printer list ], ... }
  663.  
  664.  
  665. def getSupportedCUPSPrinters(back_end_filter=['hp'], filter=DEFAULT_FILTER):
  666.     printer_list = []
  667.     printers = cups.getPrinters()
  668.  
  669.     for p in printers:
  670.         try:
  671.             back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
  672.                 parseDeviceURI(p.device_uri)
  673.  
  674.         except Error:
  675.             continue
  676.  
  677.         if (back_end_filter == '*' or back_end in back_end_filter) and model and is_hp:
  678.             include = True
  679.             mq = queryModelByModel(model)
  680.  
  681.             if not mq:
  682.                 log.debug("Not found.")
  683.                 include = False
  684.  
  685.             elif int(mq.get('support-type', SUPPORT_TYPE_NONE)) == SUPPORT_TYPE_NONE:
  686.                 log.debug("Not supported.")
  687.                 include = False
  688.  
  689.             elif filter not in (None, 'print', 'print-type'):
  690.                 include = __checkFilter(filter, mq)
  691.  
  692.             if include:
  693.                 p.name = p.name.decode('utf-8')
  694.                 printer_list.append(p)
  695.             #printer_list[p.name] = p.device_uri
  696.  
  697.     return printer_list # [ cupsext.Printer, ... ]
  698.  
  699.  
  700. def getSupportedCUPSPrinterNames(back_end_filter=['hp'], filter=DEFAULT_FILTER):
  701.     printers = getSupportedCUPSPrinters(back_end_filter, filter)
  702.     return [p.name for p in printers]
  703.  
  704.  
  705. def getDeviceURIByPrinterName(printer_name, scan_uri_flag=False):
  706.     if printer_name is None:
  707.         return None
  708.  
  709.     device_uri = None
  710.     printers = cups.getPrinters()
  711.  
  712.     for p in printers:
  713.         try:
  714.             back_end, is_hp, bus, model, serial, dev_file, host, zc, port = \
  715.                 parseDeviceURI(p.device_uri)
  716.  
  717.         except Error:
  718.             continue
  719.  
  720.         if is_hp and p.name == printer_name:
  721.             if scan_uri_flag:
  722.                 device_uri = p.device_uri.replace('hp:', 'hpaio:')
  723.             else:
  724.                 device_uri = p.device_uri
  725.             break
  726.  
  727.     return device_uri
  728.  
  729. #
  730. # IEEE-1284 Device ID parsing
  731. #
  732.  
  733. def parseDeviceID(device_id):
  734.     d= {}
  735.     x = [y.strip() for y in device_id.strip().split(';') if y]
  736.  
  737.     for z in x:
  738.         y = z.split(':')
  739.         try:
  740.             d.setdefault(y[0].strip(), y[1])
  741.         except IndexError:
  742.             d.setdefault(y[0].strip(), None)
  743.  
  744.     d.setdefault('MDL', '')
  745.     d.setdefault('SN',  '')
  746.  
  747.     if 'MODEL' in d:
  748.         d['MDL'] = d['MODEL']
  749.         del d['MODEL']
  750.  
  751.     if 'SERIAL' in d:
  752.         d['SN'] = d['SERIAL']
  753.         del d['SERIAL']
  754.  
  755.     elif 'SERN' in d:
  756.         d['SN'] = d['SERN']
  757.         del d['SERN']
  758.  
  759.     if d['SN'].startswith('X'):
  760.         d['SN'] = ''
  761.  
  762.     return d
  763.  
  764. #
  765. # IEEE-1284 Device ID Dynamic Counter Parsing
  766. #
  767.  
  768. def parseDynamicCounter(ctr_field, convert_to_int=True):
  769.     counter, value = ctr_field.split(' ')
  770.     try:
  771.         counter = int(utils.xlstrip(str(counter), '0') or '0')
  772.  
  773.         if convert_to_int:
  774.             value = int(utils.xlstrip(str(value), '0') or '0')
  775.     except ValueError:
  776.         if convert_to_int:
  777.             counter, value = 0, 0
  778.         else:
  779.             counter, value = 0, ''
  780.  
  781.     return counter, value
  782.  
  783.  
  784. #
  785. # Parse Device URI Strings
  786. #
  787.  
  788. def parseDeviceURI(device_uri):
  789.     m = pat_deviceuri.match(device_uri)
  790.  
  791.     if m is None:
  792.         log.debug("Device URI %s is invalid/unknown" % device_uri)
  793.         raise Error(ERROR_INVALID_DEVICE_URI)
  794.  
  795.     back_end = m.group(1).lower() or ''
  796.     is_hp = (back_end in ('hp', 'hpfax', 'hpaio'))
  797.     bus = m.group(2).lower() or ''
  798.  
  799.     if bus not in ('usb', 'net', 'bt', 'fw', 'par'):
  800.         log.debug("Device URI %s is invalid/unknown" % device_uri)
  801.         raise Error(ERROR_INVALID_DEVICE_URI)
  802.  
  803.     model = m.group(3) or ''
  804.     serial = m.group(4) or ''
  805.     dev_file = m.group(5) or ''
  806.     host = m.group(6) or ''
  807.     zc = ''
  808.     if not host:
  809.         zc = host = m.group(7) or ''
  810.     port = m.group(8) or 1
  811.  
  812.     if bus == 'net':
  813.         try:
  814.             port = int(port)
  815.         except (ValueError, TypeError):
  816.             port = 1
  817.  
  818.         if port == 0:
  819.             port = 1
  820.  
  821.     log.debug("%s: back_end:%s is_hp:%s bus:%s model:%s serial:%s dev_file:%s host:%s zc:%s port:%s" %
  822.         (device_uri, back_end, is_hp, bus, model, serial, dev_file, host, zc, port))
  823.  
  824.     return back_end, is_hp, bus, model, serial, dev_file, host, zc, port
  825.  
  826.  
  827. def isLocal(bus):
  828.     return bus in ('par', 'usb', 'fw', 'bt')
  829.  
  830.  
  831. def isNetwork(bus):
  832.     return bus in ('net',)
  833.  
  834.  
  835. #
  836. # Misc
  837. #
  838.  
  839. def __checkFilter(filter, mq):
  840.     for f, p in filter.items():
  841.         if f is not None:
  842.             op, val = p
  843.             if not op(mq[f], val):
  844.                 return False
  845.  
  846.     return True
  847.  
  848.  
  849. def validateBusList(bus, allow_cups=True):
  850.     for b in bus:
  851.         if allow_cups:
  852.             vb = VALID_BUSES
  853.         else:
  854.             vb = VALID_BUSES_WO_CUPS
  855.  
  856.         if b not in vb:
  857.             log.error("Invalid bus name: %s" %b)
  858.             return False
  859.  
  860.     return True
  861.  
  862.  
  863. def validateFilterList(filter):
  864.     if filter is None:
  865.         return True
  866.  
  867.     for f in filter:
  868.         if f not in VALID_FILTERS:
  869.             log.error("Invalid term '%s' in filter list" % f)
  870.             return False
  871.  
  872.     return True
  873.  
  874.  
  875. #
  876. # UI String Queries (why is this here?)
  877. #
  878.  
  879. inter_pat = re.compile(r"""%(.*)%""", re.IGNORECASE)
  880. st = StringTable()
  881. strings_init = False
  882.  
  883.  
  884. def initStrings():
  885.     global strings_init, st
  886.     strings_init = True
  887.     cycles = 0
  888.  
  889.     while True:
  890.         found = False
  891.  
  892.         for s in st.string_table:
  893.             short_string, long_string = st.string_table[s]
  894.             short_replace, long_replace = short_string, long_string
  895.  
  896.             try:
  897.                 short_match = inter_pat.match(short_string).group(1)
  898.             except (AttributeError, TypeError):
  899.                 short_match = None
  900.  
  901.             if short_match is not None:
  902.                 found = True
  903.  
  904.                 try:
  905.                     short_replace, dummy = st.string_table[short_match]
  906.                 except KeyError:
  907.                     log.error("String interpolation error: %s" % short_match)
  908.  
  909.             try:
  910.                 long_match = inter_pat.match(long_string).group(1)
  911.             except (AttributeError, TypeError):
  912.                 long_match = None
  913.  
  914.             if long_match is not None:
  915.                 found = True
  916.  
  917.                 try:
  918.                     dummy, long_replace = st.string_table[long_match]
  919.                 except KeyError:
  920.                     log.error("String interpolation error: %s" % long_match)
  921.  
  922.             if found:
  923.                 st.string_table[s] = (short_replace, long_replace)
  924.  
  925.         if not found:
  926.             break
  927.         else:
  928.             cycles +=1
  929.             if cycles > 1000:
  930.                 break
  931.  
  932.  
  933. def queryString(string_id, typ=0):
  934.     if not strings_init:
  935.         initStrings()
  936.  
  937.     #log.debug("queryString(%s)" % string_id)
  938.     s = st.string_table.get(str(string_id), ('', ''))[typ]
  939.  
  940.     if type(s) == type(''):
  941.         return s
  942.  
  943.     return s()
  944.  
  945.  
  946. AGENT_types = { AGENT_TYPE_NONE        : 'invalid',
  947.                 AGENT_TYPE_BLACK       : 'black',
  948.                 AGENT_TYPE_CMY         : 'cmy',
  949.                 AGENT_TYPE_KCM         : 'kcm',
  950.                 AGENT_TYPE_CYAN        : 'cyan',
  951.                 AGENT_TYPE_MAGENTA     : 'magenta',
  952.                 AGENT_TYPE_YELLOW      : 'yellow',
  953.                 AGENT_TYPE_CYAN_LOW    : 'photo_cyan',
  954.                 AGENT_TYPE_MAGENTA_LOW : 'photo_magenta',
  955.                 AGENT_TYPE_YELLOW_LOW  : 'photo_yellow',
  956.                 AGENT_TYPE_GGK         : 'photo_gray',
  957.                 AGENT_TYPE_BLUE        : 'photo_blue',
  958.                 AGENT_TYPE_KCMY_CM     : 'kcmy_cm',
  959.                 AGENT_TYPE_LC_LM       : 'photo_cyan_and_photo_magenta',
  960.                 #AGENT_TYPE_Y_M         : 'yellow_and_magenta',
  961.                 #AGENT_TYPE_C_K         : 'cyan_and_black',
  962.                 AGENT_TYPE_LG_PK       : 'light_gray_and_photo_black',
  963.                 AGENT_TYPE_LG          : 'light_gray',
  964.                 AGENT_TYPE_G           : 'medium_gray',
  965.                 AGENT_TYPE_PG          : 'photo_gray',
  966.                 AGENT_TYPE_C_M         : 'cyan_and_magenta',
  967.                 AGENT_TYPE_K_Y         : 'black_and_yellow',
  968.                 AGENT_TYPE_UNSPECIFIED : 'unspecified', # Kind=5,6
  969.             }
  970.  
  971. AGENT_kinds = {AGENT_KIND_NONE            : 'invalid',
  972.                 AGENT_KIND_HEAD            : 'head',
  973.                 AGENT_KIND_SUPPLY          : 'supply',
  974.                 AGENT_KIND_HEAD_AND_SUPPLY : 'cartridge',
  975.                 AGENT_KIND_TONER_CARTRIDGE : 'toner',
  976.                 AGENT_KIND_MAINT_KIT       : 'maint_kit', # fuser
  977.                 AGENT_KIND_ADF_KIT         : 'adf_kit',
  978.                 AGENT_KIND_DRUM_KIT        : 'drum_kit',
  979.                 AGENT_KIND_TRANSFER_KIT    : 'transfer_kit',
  980.                 AGENT_KIND_INT_BATTERY     : 'battery',
  981.                 AGENT_KIND_UNKNOWN         : 'unknown',
  982.               }
  983.  
  984. AGENT_healths = {AGENT_HEALTH_OK           : 'ok',
  985.                   AGENT_HEALTH_MISINSTALLED : 'misinstalled', # supply/cart
  986.                   #AGENT_HEALTH_FAIR_MODERATE : '',
  987.                   AGENT_HEALTH_INCORRECT    : 'incorrect',
  988.                   AGENT_HEALTH_FAILED       : 'failed',
  989.                   AGENT_HEALTH_OVERTEMP     : 'overtemp', # battery
  990.                   AGENT_HEALTH_CHARGING     : 'charging', # battery
  991.                   AGENT_HEALTH_DISCHARGING  : 'discharging', # battery
  992.                 }
  993.  
  994.  
  995. AGENT_levels = {AGENT_LEVEL_TRIGGER_MAY_BE_LOW : 'low',
  996.                  AGENT_LEVEL_TRIGGER_PROBABLY_OUT : 'low',
  997.                  AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT : 'out',
  998.                }
  999.  
  1000.  
  1001. #
  1002.  
  1003.  
  1004.  
  1005. # **************************************************************************** #
  1006.  
  1007. string_cache = {}
  1008.  
  1009. class Device(object):
  1010.     def __init__(self, device_uri, printer_name=None,
  1011.                  service=None, callback=None, disable_dbus=False):
  1012.  
  1013.         log.debug("Device URI: %s" % device_uri)
  1014.         log.debug("Printer: %s" % printer_name)
  1015.  
  1016.         global dbus_disabled
  1017.         dbus_disabled = disable_dbus
  1018.  
  1019.         if not disable_dbus:
  1020.             if service is None:
  1021.                 self.dbus_avail, self.service,  session_bus = init_dbus()
  1022.             else:
  1023.                 self.dbus_avail = True
  1024.                 self.service = service
  1025.         else:
  1026.             self.dbus_avail = False
  1027.             self.service = None
  1028.  
  1029.         self.last_event = None # Used in devmgr if dbus is disabled
  1030.  
  1031.         printers = cups.getPrinters()
  1032.  
  1033.         if device_uri is None and printer_name is not None:
  1034.             for p in printers:
  1035.                 if p.name.lower() == printer_name.lower():
  1036.                     device_uri = p.device_uri
  1037.                     log.debug("Device URI: %s" % device_uri)
  1038.                     break
  1039.             else:
  1040.                 raise Error(ERROR_DEVICE_NOT_FOUND)
  1041.  
  1042.         self.device_uri = device_uri
  1043.         self.callback = callback
  1044.         self.device_type = DEVICE_TYPE_UNKNOWN
  1045.  
  1046.         if self.device_uri is None:
  1047.             raise Error(ERROR_DEVICE_NOT_FOUND)
  1048.  
  1049.         if self.device_uri.startswith('hp:'):
  1050.             self.device_type = DEVICE_TYPE_PRINTER
  1051.  
  1052.         elif self.device_uri.startswith('hpaio:'):
  1053.             self.device_type = DEVICE_TYPE_SCANNER
  1054.  
  1055.         elif self.device_uri.startswith('hpfax:'):
  1056.             self.device_type = DEVICE_TYPE_FAX
  1057.  
  1058.         try:
  1059.             self.back_end, self.is_hp, self.bus, self.model, \
  1060.                 self.serial, self.dev_file, self.host, self.zc, self.port = \
  1061.                 parseDeviceURI(self.device_uri)
  1062.         except Error:
  1063.             self.io_state = IO_STATE_NON_HP
  1064.             raise Error(ERROR_INVALID_DEVICE_URI)
  1065.  
  1066.         log.debug("URI: backend=%s, is_hp=%s, bus=%s, model=%s, serial=%s, dev=%s, host=%s, port=%d" % \
  1067.             (self.back_end, self.is_hp, self.bus, self.model, self.serial, self.dev_file, self.host, self.port))
  1068.  
  1069.         self.model_ui = models.normalizeModelUIName(self.model)
  1070.         self.model = models.normalizeModelName(self.model)
  1071.  
  1072.         log.debug("Model/UI model: %s/%s" % (self.model, self.model_ui))
  1073.  
  1074.         # TODO:
  1075.         #service.setAlertsEx(self.hpssd_sock)
  1076.  
  1077.         self.mq = {} # Model query
  1078.         self.dq = {} # Device query
  1079.         self.icon = "default_printer"
  1080.         self.cups_printers = []
  1081.         self.channels = {} # { 'SERVICENAME' : channel_id, ... }
  1082.         self.device_id = -1
  1083.         self.r_values = None # ( r_value, r_value_str, rg, rr )
  1084.         self.deviceID = ''
  1085.         self.panel_check = True
  1086.         self.io_state = IO_STATE_HP_READY
  1087.         self.is_local = isLocal(self.bus)
  1088.         self.hist = []
  1089.  
  1090.         self.supported = False
  1091.  
  1092.         self.queryModel()
  1093.         if not self.supported:
  1094.             log.error("Unsupported model: %s" % self.model)
  1095.             self.error_code = STATUS_DEVICE_UNSUPPORTED
  1096.             self.sendEvent(self.error_code)
  1097.         else:
  1098.             self.supported = True
  1099.  
  1100.  
  1101.         self.mq.update({'model'    : self.model,
  1102.                         'model-ui' : self.model_ui})
  1103.  
  1104.         self.error_state = ERROR_STATE_ERROR
  1105.         self.device_state = DEVICE_STATE_NOT_FOUND
  1106.         self.status_code = EVENT_ERROR_DEVICE_NOT_FOUND
  1107.  
  1108.         self.updateCUPSPrinters()
  1109.  
  1110.         if self.mq.get('fax-type', FAX_TYPE_NONE) != FAX_TYPE_NONE:
  1111.             self.dq.update({ 'fax-uri' : self.device_uri.replace('hp:/', 'hpfax:/').replace('hpaio:/', 'hpfax:/')})
  1112.  
  1113.         if self.mq.get('scan-type', SCAN_TYPE_NONE) != SCAN_TYPE_NONE:
  1114.             self.dq.update({ 'scan-uri' : self.device_uri.replace('hp:/', 'hpaio:/').replace('hpfax:/', 'hpaio:/')})
  1115.  
  1116.         self.dq.update({
  1117.             'back-end'         : self.back_end,
  1118.             'is-hp'            : self.is_hp,
  1119.             'serial'           : self.serial,
  1120.             'dev-file'         : self.dev_file,
  1121.             'host'             : self.host,
  1122.             'port'             : self.port,
  1123.             'cups-printers'    : ','.join(self.cups_printers),
  1124.             'status-code'      : self.status_code,
  1125.             'status-desc'      : '',
  1126.             'deviceid'         : '',
  1127.             'panel'            : 0,
  1128.             'panel-line1'      : '',
  1129.             'panel-line2'      : '',
  1130.             'device-state'     : self.device_state,
  1131.             'error-state'      : self.error_state,
  1132.             'device-uri'       : self.device_uri,
  1133.             'cups-uri'         : self.device_uri.replace('hpfax:/', 'hp:/').replace('hpaio:/', 'hp:/'),
  1134.             })
  1135.  
  1136.         self.device_vars = {
  1137.             'URI'        : self.device_uri,
  1138.             'DEVICE_URI' : self.device_uri,
  1139.             'SCAN_URI'   : self.device_uri.replace('hp:', 'hpaio:'),
  1140.             'SANE_URI'   : self.device_uri.replace('hp:', 'hpaio:'),
  1141.             'FAX_URI'    : self.device_uri.replace('hp:', 'hpfax:'),
  1142.             'PRINTER'    : self.first_cups_printer,
  1143.             'HOME'       : prop.home_dir,
  1144.                            }
  1145.  
  1146.  
  1147.  
  1148.  
  1149.     def sendEvent(self, event_code, printer_name='', job_id=0, title=''):
  1150.         if self.dbus_avail and self.service is not None:
  1151.             try:
  1152.                 log.debug("Sending event %d to hpssd..." % event_code)
  1153.                 self.service.SendEvent(self.device_uri, printer_name, event_code, prop.username, job_id, title)
  1154.             except dbus.exceptions.DBusException, e:
  1155.                 log.debug("dbus call to SendEvent() failed.")
  1156.  
  1157.  
  1158.     def quit(self):
  1159.         pass
  1160.  
  1161.  
  1162.     def queryModel(self):
  1163.         if not self.mq:
  1164.             self.mq = queryModelByURI(self.device_uri)
  1165.  
  1166.         self.supported = bool(self.mq)
  1167.  
  1168.         if self.supported:
  1169.             for m in self.mq:
  1170.                 self.__dict__[m.replace('-','_')] = self.mq[m]
  1171.  
  1172.  
  1173.     def queryString(self, string_id):
  1174.         return queryString(string_id)
  1175.  
  1176.  
  1177.     def open(self, open_for_printing=False):
  1178.         if self.supported and self.io_state in (IO_STATE_HP_READY, IO_STATE_HP_NOT_AVAIL):
  1179.             prev_device_state = self.device_state
  1180.             self.io_state = IO_STATE_HP_NOT_AVAIL
  1181.             self.device_state = DEVICE_STATE_NOT_FOUND
  1182.             self.error_state = ERROR_STATE_ERROR
  1183.             self.status_code = EVENT_ERROR_DEVICE_NOT_FOUND
  1184.             self.device_id = -1
  1185.             self.open_for_printing = open_for_printing
  1186.  
  1187.             if open_for_printing:
  1188.                 log.debug("Opening device: %s (for printing)" % self.device_uri)
  1189.                 self.io_mode = self.mq.get('io-mode', hpmudext.HPMUD_UNI_MODE)
  1190.             else:
  1191.                 log.debug("Opening device: %s (not for printing)" % self.device_uri)
  1192.                 self.io_mode = self.mq.get('io-mfp-mode', hpmudext.HPMUD_UNI_MODE)
  1193.  
  1194.             log.debug("I/O mode=%d" % self.io_mode)
  1195.             result_code, self.device_id = \
  1196.                 hpmudext.open_device(self.device_uri, self.io_mode)
  1197.  
  1198.             if result_code != hpmudext.HPMUD_R_OK:
  1199.                 self.error_state = ERROR_STATE_ERROR
  1200.                 self.error_code = result_code+ERROR_CODE_BASE
  1201.                 self.sendEvent(self.error_code)
  1202.  
  1203.                 if result_code == hpmudext.HPMUD_R_DEVICE_BUSY:
  1204.                     log.error("Device busy: %s" % self.device_uri)
  1205.                 else:
  1206.                     log.error("Unable to communicate with device (code=%d): %s" % (result_code, self.device_uri))
  1207.  
  1208.                 self.last_event = Event(self.device_uri, '', EVENT_ERROR_DEVICE_NOT_FOUND,
  1209.                         prop.username, 0, '', time.time())
  1210.  
  1211.                 raise Error(ERROR_DEVICE_NOT_FOUND)
  1212.  
  1213.             else:
  1214.                 log.debug("device-id=%d" % self.device_id)
  1215.                 self.io_state = IO_STATE_HP_OPEN
  1216.                 self.error_state = ERROR_STATE_CLEAR
  1217.                 log.debug("Opened device: %s (backend=%s, is_hp=%s, bus=%s, model=%s, dev=%s, serial=%s, host=%s, port=%d)" %
  1218.                     (self.back_end, self.device_uri, self.is_hp, self.bus, self.model,
  1219.                      self.dev_file, self.serial, self.host, self.port))
  1220.  
  1221.                 if prev_device_state == DEVICE_STATE_NOT_FOUND:
  1222.                     self.device_state = DEVICE_STATE_JUST_FOUND
  1223.                 else:
  1224.                     self.device_state = DEVICE_STATE_FOUND
  1225.  
  1226.                 self.getDeviceID()
  1227.                 self.getSerialNumber()
  1228.                 return self.device_id
  1229.  
  1230.  
  1231.     def close(self):
  1232.         if self.io_state == IO_STATE_HP_OPEN:
  1233.             log.debug("Closing device...")
  1234.  
  1235.             if len(self.channels) > 0:
  1236.  
  1237.                 for c in self.channels.keys():
  1238.                     self.__closeChannel(c)
  1239.  
  1240.             result_code = hpmudext.close_device(self.device_id)
  1241.             log.debug("Result-code = %d" % result_code)
  1242.  
  1243.             self.channels.clear()
  1244.             self.io_state = IO_STATE_HP_READY
  1245.  
  1246.  
  1247.     def __openChannel(self, service_name):
  1248.         try:
  1249.             if self.io_state == IO_STATE_HP_OPEN:
  1250.                 if service_name == hpmudext.HPMUD_S_PRINT_CHANNEL and not self.open_for_printing:
  1251.                     self.close()
  1252.                     self.open(True)
  1253.                 elif service_name != hpmudext.HPMUD_S_PRINT_CHANNEL and self.open_for_printing:
  1254.                     self.close()
  1255.                     self.open(False)
  1256.             else:
  1257.                 self.open(service_name == hpmudext.HPMUD_S_PRINT_CHANNEL)
  1258.         except:
  1259.             log.error("unable to open channel")
  1260.             return -1
  1261.  
  1262.         #if not self.mq['io-mode'] == IO_MODE_UNI:
  1263.         if 1:
  1264.             service_name = service_name.upper()
  1265.  
  1266.             if service_name not in self.channels:
  1267.                 log.debug("Opening %s channel..." % service_name)
  1268.  
  1269.                 result_code, channel_id = hpmudext.open_channel(self.device_id, service_name)
  1270.  
  1271.                 self.channels[service_name] = channel_id
  1272.                 log.debug("channel-id=%d" % channel_id)
  1273.                 return channel_id
  1274.             else:
  1275.                 return self.channels[service_name]
  1276.         else:
  1277.             return -1
  1278.  
  1279.  
  1280.     def openChannel(self, service_name):
  1281.         return self.__openChannel(service_name)
  1282.  
  1283.     def openPrint(self):
  1284.         return self.__openChannel(hpmudext.HPMUD_S_PRINT_CHANNEL)
  1285.  
  1286.     def openFax(self):
  1287.         return self.__openChannel(hpmudext.HPMUD_S_FAX_SEND_CHANNEL)
  1288.  
  1289.     def openPCard(self):
  1290.         return self.__openChannel(hpmudext.HPMUD_S_MEMORY_CARD_CHANNEL)
  1291.  
  1292.     def openEWS(self):
  1293.         return self.__openChannel(hpmudext.HPMUD_S_EWS_CHANNEL)
  1294.  
  1295.     def closePrint(self):
  1296.         return self.__closeChannel(hpmudext.HPMUD_S_PRINT_CHANNEL)
  1297.  
  1298.     def closePCard(self):
  1299.         return self.__closeChannel(hpmudext.HPMUD_S_MEMORY_CARD_CHANNEL)
  1300.  
  1301.     def closeFax(self):
  1302.         return self.__closeChannel(hpmudext.HPMUD_S_FAX_SEND_CHANNEL)
  1303.  
  1304.     def openPML(self):
  1305.         return self.__openChannel(hpmudext.HPMUD_S_PML_CHANNEL)
  1306.  
  1307.     def openWifiConfig(self):
  1308.         return self.__openChannel(hpmudext.HPMUD_S_WIFI_CHANNEL)
  1309.  
  1310.     def closePML(self):
  1311.         return self.__closeChannel(hpmudext.HPMUD_S_PML_CHANNEL)
  1312.  
  1313.     def closeEWS(self):
  1314.         return self.__closeChannel(hpmudext.HPMUD_S_EWS_CHANNEL)
  1315.  
  1316.     def openCfgUpload(self):
  1317.         return self.__openChannel(hpmudext.HPMUD_S_CONFIG_UPLOAD_CHANNEL)
  1318.  
  1319.     def closeCfgUpload(self):
  1320.         return self.__closeChannel(hpmudext.HPMUD_S_CONFIG_UPLOAD_CHANNEL)
  1321.  
  1322.     def openCfgDownload(self):
  1323.         return self.__openChannel(hpmudext.HPMUD_S_CONFIG_DOWNLOAD_CHANNEL)
  1324.  
  1325.     def closeCfgDownload(self):
  1326.         return self.__closeChannel(hpmudext.HPMUD_S_CONFIG_DOWNLOAD_CHANNEL)
  1327.  
  1328.     def openSoapFax(self):
  1329.         return self.__openChannel(hpmudext.HPMUD_S_SOAP_FAX)
  1330.  
  1331.     def closeSoapFax(self):
  1332.         return self.__closeChannel(hpmudext.HPMUD_S_SOAP_FAX)
  1333.  
  1334.     def closeWifiConfig(self):
  1335.         return self.__closeChannel(hpmudext.HPMUD_S_WIFI_CHANNEL)
  1336.  
  1337.     def __closeChannel(self, service_name):
  1338.         #if not self.mq['io-mode'] == IO_MODE_UNI and \
  1339.         if self.io_state == IO_STATE_HP_OPEN:
  1340.  
  1341.             service_name = service_name.upper()
  1342.  
  1343.             if service_name in self.channels:
  1344.                 log.debug("Closing %s channel..." % service_name)
  1345.  
  1346.                 result_code = hpmudext.close_channel(self.device_id,
  1347.                     self.channels[service_name])
  1348.  
  1349.                 del self.channels[service_name]
  1350.  
  1351.  
  1352.     def closeChannel(self, service_name):
  1353.         return self.__closeChannel(service_name)
  1354.  
  1355.  
  1356.     def getDeviceID(self):
  1357.         needs_close = False
  1358.         if self.io_state != IO_STATE_HP_OPEN:
  1359.            try:
  1360.                self.open()
  1361.            except:
  1362.                return -1
  1363.            needs_close = True
  1364.  
  1365.         result_code, data = hpmudext.get_device_id(self.device_id)
  1366.  
  1367.         if result_code != hpmudext.HPMUD_R_OK:
  1368.             self.raw_deviceID = ''
  1369.             self.deviceID = {}
  1370.         else:
  1371.             self.raw_deviceID = data
  1372.             self.deviceID = parseDeviceID(data)
  1373.  
  1374.         if needs_close:
  1375.             self.close()
  1376.  
  1377.         return self.deviceID
  1378.  
  1379.  
  1380.     def getSerialNumber(self):
  1381.         if self.serial:
  1382.             return
  1383.  
  1384.         try:
  1385.             self.serial = self.deviceID['SN']
  1386.         except KeyError:
  1387.             pass
  1388.         else:
  1389.             if self.serial:
  1390.                 return
  1391.  
  1392.         if self.mq.get('status-type', STATUS_TYPE_NONE) != STATUS_TYPE_NONE: # and \
  1393.             #not self.mq.get('io-mode', IO_MODE_UNI) == IO_MODE_UNI:
  1394.  
  1395.             try:
  1396.                 try:
  1397.                     error_code, self.serial = self.getPML(pml.OID_SERIAL_NUMBER)
  1398.                 except Error:
  1399.                     self.serial = ''
  1400.             finally:
  1401.                 self.closePML()
  1402.  
  1403.         if self.serial is None:
  1404.             self.serial = ''
  1405.  
  1406.  
  1407.     def getThreeBitStatus(self):
  1408.         pass
  1409.  
  1410.  
  1411.     def getStatusFromDeviceID(self):
  1412.         self.getDeviceID()
  1413.         return status.parseStatus(parseDeviceID(self.raw_deviceID))
  1414.  
  1415.  
  1416.     def __parseRValues(self, r_value):
  1417.         r_value_str = str(r_value)
  1418.         r_value_str = ''.join(['0'*(9 - len(r_value_str)), r_value_str])
  1419.         rg, rr = r_value_str[:3], r_value_str[3:]
  1420.         r_value = int(rr)
  1421.         self.r_values = r_value, r_value_str, rg, rr
  1422.         return r_value, r_value_str, rg, rr
  1423.  
  1424.  
  1425.     def getRValues(self, r_type, status_type, dynamic_counters):
  1426.         r_value, r_value_str, rg, rr = 0, '000000000', '000', '000000'
  1427.  
  1428.         if r_type > 0 and \
  1429.             dynamic_counters != STATUS_DYNAMIC_COUNTERS_NONE:
  1430.  
  1431.             if self.r_values is None:
  1432.                 if self.dbus_avail:
  1433.                     try:
  1434.                         r_value = int(self.service.GetCachedIntValue(self.device_uri, 'r_value'))
  1435.                     except dbus.exceptions.DBusException, e:
  1436.                         log.debug("dbus call to GetCachedIntValue() failed.")
  1437.                         r_value = -1
  1438.  
  1439.                 if r_value != -1:
  1440.                     log.debug("r_value=%d" % r_value)
  1441.                     r_value, r_value_str, rg, rr = self.__parseRValues(r_value)
  1442.  
  1443.                     return r_value, r_value_str, rg, rr
  1444.  
  1445.             if self.r_values is None:
  1446.  
  1447.                 if status_type ==  STATUS_TYPE_S and \
  1448.                     self.is_local and \
  1449.                     dynamic_counters != STATUS_DYNAMIC_COUNTERS_PML_SNMP:
  1450.  
  1451.                     try:
  1452.                         try:
  1453.                             r_value = self.getDynamicCounter(140)
  1454.  
  1455.                             if r_value is not None:
  1456.                                 log.debug("r_value=%d" % r_value)
  1457.                                 r_value, r_value_str, rg, rr = self.__parseRValues(r_value)
  1458.  
  1459.                                 if self.dbus_avail:
  1460.                                     try:
  1461.                                         self.service.SetCachedIntValue(self.device_uri, 'r_value', r_value)
  1462.                                     except dbus.exceptions.DBusException, e:
  1463.                                         log.debug("dbus call to SetCachedIntValue() failed.")
  1464.                             else:
  1465.                                 log.error("Error attempting to read r-value (2).")
  1466.                                 r_value = 0
  1467.                         except Error:
  1468.                             log.error("Error attempting to read r-value (1).")
  1469.                             r_value = 0
  1470.                     finally:
  1471.                         self.closePrint()
  1472.  
  1473.  
  1474.                 elif (status_type ==  STATUS_TYPE_S and
  1475.                       dynamic_counters == STATUS_DYNAMIC_COUNTERS_PCL and
  1476.                       not self.is_local) or \
  1477.                       dynamic_counters == STATUS_DYNAMIC_COUNTERS_PML_SNMP:
  1478.  
  1479.                     try:
  1480.                         result_code, r_value = self.getPML(pml.OID_R_SETTING)
  1481.  
  1482.                         if r_value is not None:
  1483.                             log.debug("r_value=%d" % r_value)
  1484.                             r_value, r_value_str, rg, rr = self.__parseRValues(r_value)
  1485.  
  1486.                             if self.dbus_avail:
  1487.                                 try:
  1488.                                     self.service.SetCachedIntValue(self.device_uri, 'r_value', r_value)
  1489.                                 except dbus.exceptions.DBusException, e:
  1490.                                     log.debug("dbus call to SetCachedIntValue() failed.")
  1491.  
  1492.                         else:
  1493.                             r_value = 0
  1494.  
  1495.                     finally:
  1496.                         self.closePML()
  1497.  
  1498.             else:
  1499.                 r_value, r_value_str, rg, rr = self.r_values
  1500.  
  1501.         return r_value, r_value_str, rg, rr
  1502.  
  1503.  
  1504.     def __queryFax(self, quick=False, reread_cups_printers=False):
  1505.         io_mode = self.mq.get('io-mode', IO_MODE_UNI)
  1506.         self.status_code = STATUS_PRINTER_IDLE
  1507.  
  1508.         if io_mode != IO_MODE_UNI:
  1509.  
  1510.             if self.device_state != DEVICE_STATE_NOT_FOUND:
  1511.                 if self.tech_type in (TECH_TYPE_MONO_INK, TECH_TYPE_COLOR_INK):
  1512.                     try:
  1513.                         self.getDeviceID()
  1514.                     except Error, e:
  1515.                         log.error("Error getting device ID.")
  1516.                         self.last_event = Event(self.device_uri, '', ERROR_DEVICE_IO_ERROR,
  1517.                             prop.username, 0, '', time.time())
  1518.  
  1519.                         raise Error(ERROR_DEVICE_IO_ERROR)
  1520.  
  1521.                 status_desc = self.queryString(self.status_code)
  1522.  
  1523.                 self.dq.update({
  1524.                     'serial'           : self.serial,
  1525.                     'cups-printers'    : ','.join(self.cups_printers),
  1526.                     'status-code'      : self.status_code,
  1527.                     'status-desc'      : status_desc,
  1528.                     'deviceid'         : self.raw_deviceID,
  1529.                     'panel'            : 0,
  1530.                     'panel-line1'      : '',
  1531.                     'panel-line2'      : '',
  1532.                     'device-state'     : self.device_state,
  1533.                     'error-state'      : self.error_state,
  1534.                     })
  1535.  
  1536.  
  1537.             log.debug("Fax activity check...")
  1538.  
  1539.             tx_active, rx_active = status.getFaxStatus(self)
  1540.  
  1541.             if tx_active:
  1542.                 self.status_code = STATUS_FAX_TX_ACTIVE
  1543.             elif rx_active:
  1544.                 self.status_code = STATUS_FAX_RX_ACTIVE
  1545.  
  1546.             self.error_state = STATUS_TO_ERROR_STATE_MAP.get(self.status_code, ERROR_STATE_CLEAR)
  1547.             self.error_code = self.status_code
  1548.             self.sendEvent(self.error_code)
  1549.  
  1550.             try:
  1551.                 self.dq.update({'status-desc' : self.queryString(self.status_code),
  1552.                                 'error-state' : self.error_state,
  1553.                                 })
  1554.  
  1555.             except (KeyError, Error):
  1556.                 self.dq.update({'status-desc' : '',
  1557.                                 'error-state' : ERROR_STATE_CLEAR,
  1558.                                 })
  1559.  
  1560.  
  1561.             if self.panel_check:
  1562.                 self.panel_check = bool(self.mq.get('panel-check-type', 0))
  1563.  
  1564.             status_type = self.mq.get('status-type', STATUS_TYPE_NONE)
  1565.             if self.panel_check and \
  1566.                 status_type in (STATUS_TYPE_LJ, STATUS_TYPE_S, STATUS_TYPE_VSTATUS) and \
  1567.                 io_mode != IO_MODE_UNI:
  1568.  
  1569.                 log.debug("Panel check...")
  1570.                 try:
  1571.                     self.panel_check, line1, line2 = status.PanelCheck(self)
  1572.                 finally:
  1573.                     self.closePML()
  1574.  
  1575.                 self.dq.update({'panel': int(self.panel_check),
  1576.                                   'panel-line1': line1,
  1577.                                   'panel-line2': line2,})
  1578.  
  1579.             if not quick and reread_cups_printers:
  1580.                 self.updateCUPSPrinters()
  1581.  
  1582.         for d in self.dq:
  1583.             self.__dict__[d.replace('-','_')] = self.dq[d]
  1584.  
  1585.         self.last_event = Event(self.device_uri, '', self.status_code, prop.username, 0, '', time.time())
  1586.  
  1587.         log.debug(self.dq)
  1588.  
  1589.  
  1590.  
  1591.     def updateCUPSPrinters(self):
  1592.         self.cups_printers = []
  1593.         log.debug("Re-reading CUPS printer queue information.")
  1594.         printers = cups.getPrinters()
  1595.         for p in printers:
  1596.             if self.device_uri == p.device_uri:
  1597.                 self.cups_printers.append(p.name)
  1598.                 self.state = p.state # ?
  1599.  
  1600.                 if self.io_state == IO_STATE_NON_HP:
  1601.                     self.model = p.makemodel.split(',')[0]
  1602.  
  1603.         self.dq.update({'cups-printers' : ','.join(self.cups_printers)})
  1604.  
  1605.         try:
  1606.             self.first_cups_printer = self.cups_printers[0]
  1607.         except IndexError:
  1608.             self.first_cups_printer = ''
  1609.  
  1610.  
  1611.  
  1612.  
  1613.     def queryDevice(self, quick=False, reread_cups_printers=False):
  1614.         if not self.supported:
  1615.             self.dq = {}
  1616.  
  1617.             self.last_event = Event(self.device_uri, '', STATUS_DEVICE_UNSUPPORTED,
  1618.                 prop.username, 0, '', time.time())
  1619.  
  1620.             return
  1621.  
  1622.         if self.device_type == DEVICE_TYPE_FAX:
  1623.             return self.__queryFax(quick, reread_cups_printers)
  1624.  
  1625.         r_type = self.mq.get('r-type', 0)
  1626.         tech_type = self.mq.get('tech-type', TECH_TYPE_NONE)
  1627.         status_type = self.mq.get('status-type', STATUS_TYPE_NONE)
  1628.         battery_check = self.mq.get('status-battery-check', STATUS_BATTERY_CHECK_NONE)
  1629.         dynamic_counters = self.mq.get('status-dynamic-counters', STATUS_DYNAMIC_COUNTERS_NONE)
  1630.         io_mode = self.mq.get('io-mode', IO_MODE_UNI)
  1631.         io_mfp_mode = self.mq.get('io-mfp-mode', IO_MODE_UNI)
  1632.         status_code = STATUS_UNKNOWN
  1633.  
  1634.         # Turn off status if local connection and bi-di not avail.
  1635.         #if io_mode  == IO_MODE_UNI and self.back_end != 'net':
  1636.         #    status_type = STATUS_TYPE_NONE
  1637.  
  1638.         agents = []
  1639.  
  1640.         if self.device_state != DEVICE_STATE_NOT_FOUND:
  1641.             if self.tech_type in (TECH_TYPE_MONO_INK, TECH_TYPE_COLOR_INK):
  1642.                 try:
  1643.                     self.getDeviceID()
  1644.                 except Error, e:
  1645.                     log.error("Error getting device ID.")
  1646.                     self.last_event = Event(self.device_uri, '', ERROR_DEVICE_IO_ERROR,
  1647.                         prop.username, 0, '', time.time())
  1648.  
  1649.                     raise Error(ERROR_DEVICE_IO_ERROR)
  1650.  
  1651.             status_desc = self.queryString(self.status_code)
  1652.  
  1653.             self.dq.update({
  1654.                 'serial'           : self.serial,
  1655.                 'cups-printers'    : ','.join(self.cups_printers),
  1656.                 'status-code'      : self.status_code,
  1657.                 'status-desc'      : status_desc,
  1658.                 'deviceid'         : self.raw_deviceID,
  1659.                 'panel'            : 0,
  1660.                 'panel-line1'      : '',
  1661.                 'panel-line2'      : '',
  1662.                 'device-state'     : self.device_state,
  1663.                 'error-state'      : self.error_state,
  1664.                 })
  1665.  
  1666.             status_block = {}
  1667.  
  1668.             if status_type == STATUS_TYPE_NONE:
  1669.                 log.warn("No status available for device.")
  1670.                 status_block = {'status-code' : STATUS_UNKNOWN}
  1671.  
  1672.             elif status_type in (STATUS_TYPE_VSTATUS, STATUS_TYPE_S):
  1673.                 log.debug("Type 1/2 (S: or VSTATUS:) status")
  1674.                 status_block = status.parseStatus(self.deviceID)
  1675.  
  1676.             elif status_type in (STATUS_TYPE_LJ, STATUS_TYPE_PML_AND_PJL):
  1677.                 log.debug("Type 3/9 LaserJet PML(+PJL) status")
  1678.                 status_block = status.StatusType3(self, self.deviceID)
  1679.  
  1680.             elif status_type == STATUS_TYPE_LJ_XML:
  1681.                 log.debug("Type 6: LJ XML")
  1682.                 status_block = status.StatusType6(self)
  1683.  
  1684.             elif status_type == STATUS_TYPE_PJL:
  1685.                 log.debug("Type 8: LJ PJL")
  1686.                 status_block = status.StatusType8(self)
  1687.  
  1688.             else:
  1689.                 log.error("Unimplemented status type: %d" % status_type)
  1690.  
  1691.             if battery_check and \
  1692.                 io_mode != IO_MODE_UNI:
  1693.  
  1694.                 log.debug("Battery check...")
  1695.                 status.BatteryCheck(self, status_block, battery_check)
  1696.  
  1697.             if status_block:
  1698.                 log.debug(status_block)
  1699.                 self.dq.update(status_block)
  1700.                 try:
  1701.                     status_block['agents']
  1702.                 except KeyError:
  1703.                     pass
  1704.                 else:
  1705.                     agents = status_block['agents']
  1706.                     del self.dq['agents']
  1707.  
  1708.  
  1709.             status_code = self.dq.get('status-code', STATUS_UNKNOWN)
  1710.  
  1711. ##            if not quick and \
  1712. ##                self.mq.get('fax-type', FAX_TYPE_NONE) and \
  1713. ##                status_code == STATUS_PRINTER_IDLE and \
  1714. ##                io_mode != IO_MODE_UNI:
  1715. ##
  1716. ##                log.debug("Fax activity check...")
  1717. ##
  1718. ##                tx_active, rx_active = status.getFaxStatus(self)
  1719. ##
  1720. ##                if tx_active:
  1721. ##                    status_code = STATUS_FAX_TX_ACTIVE
  1722. ##                elif rx_active:
  1723. ##                    status_code = STATUS_FAX_RX_ACTIVE
  1724.  
  1725.  
  1726.             self.error_state = STATUS_TO_ERROR_STATE_MAP.get(status_code, ERROR_STATE_CLEAR)
  1727.             self.error_code = status_code
  1728.             self.sendEvent(self.error_code)
  1729.  
  1730.             try:
  1731.                 self.dq.update({'status-desc' : self.queryString(status_code),
  1732.                                 'error-state' : self.error_state,
  1733.                                 })
  1734.  
  1735.             except (KeyError, Error):
  1736.                 self.dq.update({'status-desc' : '',
  1737.                                 'error-state' : ERROR_STATE_CLEAR,
  1738.                                 })
  1739.  
  1740.             r_value = 0
  1741.  
  1742.             if not quick and status_type != STATUS_TYPE_NONE:
  1743.                 if self.panel_check:
  1744.                     self.panel_check = bool(self.mq.get('panel-check-type', 0))
  1745.  
  1746.                 if self.panel_check and \
  1747.                     status_type in (STATUS_TYPE_LJ, STATUS_TYPE_S, STATUS_TYPE_VSTATUS) and \
  1748.                     io_mode != IO_MODE_UNI:
  1749.  
  1750.                     log.debug("Panel check...")
  1751.                     try:
  1752.                         self.panel_check, line1, line2 = status.PanelCheck(self)
  1753.                     finally:
  1754.                         self.closePML()
  1755.  
  1756.                     self.dq.update({'panel': int(self.panel_check),
  1757.                                       'panel-line1': line1,
  1758.                                       'panel-line2': line2,})
  1759.  
  1760.  
  1761.                 if dynamic_counters != STATUS_DYNAMIC_COUNTERS_NONE and \
  1762.                     io_mode != IO_MODE_UNI:
  1763.  
  1764.                     r_value, r_value_str, rg, rr = self.getRValues(r_type, status_type, dynamic_counters)
  1765.                 else:
  1766.                     r_value, r_value_str, rg, rr = 0, '000000000', '000', '000000'
  1767.  
  1768.                 self.dq.update({'r'  : r_value,
  1769.                                 'rs' : r_value_str,
  1770.                                 'rg' : rg,
  1771.                                 'rr' : rr,
  1772.                               })
  1773.  
  1774.             if not quick and reread_cups_printers:
  1775.                 self.updateCUPSPrinters()
  1776.  
  1777.             if not quick:
  1778.                 # Make sure there is some valid agent data for this r_value
  1779.                 # If not, fall back to r_value == 0
  1780.                 if r_value > 0 and self.mq.get('r%d-agent1-kind' % r_value, 0) == 0:
  1781.                     r_value = 0
  1782.                     self.dq.update({'r'  : r_value,
  1783.                                     'rs' : r_value_str,
  1784.                                     'rg' : rg,
  1785.                                     'rr' : rr,
  1786.                                   })
  1787.  
  1788.                 a, aa = 1, 1
  1789.                 while True:
  1790.                     mq_agent_kind = self.mq.get('r%d-agent%d-kind' % (r_value, a), -1)
  1791.  
  1792.                     if mq_agent_kind == -1:
  1793.                         break
  1794.  
  1795.                     mq_agent_type = self.mq.get('r%d-agent%d-type' % (r_value, a), 0)
  1796.                     mq_agent_sku = self.mq.get('r%d-agent%d-sku' % (r_value, a), '')
  1797.  
  1798.                     found = False
  1799.  
  1800.                     log.debug("Looking for kind=%d, type=%d..." % (mq_agent_kind, mq_agent_type))
  1801.                     for agent in agents:
  1802.                         agent_kind = agent['kind']
  1803.                         agent_type = agent['type']
  1804.  
  1805.                         if agent_kind == mq_agent_kind and \
  1806.                            agent_type == mq_agent_type:
  1807.                            found = True
  1808.                            break
  1809.  
  1810.                     if found:
  1811.                         log.debug("found: r%d-kind%d-type%d" % (r_value, agent_kind, agent_type))
  1812.  
  1813.                         agent_health = agent.get('health', AGENT_HEALTH_OK)
  1814.                         agent_level = agent.get('level', 100)
  1815.                         agent_level_trigger = agent.get('level-trigger',
  1816.                             AGENT_LEVEL_TRIGGER_SUFFICIENT_0)
  1817.  
  1818.                         log.debug("health=%d, level=%d, level_trigger=%d, status_code=%d" %
  1819.                             (agent_health, agent_level, agent_level_trigger, status_code))
  1820.  
  1821.                         query = 'agent_%s_%s' % (AGENT_types.get(agent_type, 'unknown'),
  1822.                                                  AGENT_kinds.get(agent_kind, 'unknown'))
  1823.  
  1824.                         agent_desc = self.queryString(query)
  1825.                         query = 'agent_health_ok'
  1826.  
  1827.                         # If printer is not in an error state, and
  1828.                         # if agent health is OK, check for low supplies. If low, use
  1829.                         # the agent level trigger description for the agent description.
  1830.                         # Otherwise, report the agent health.
  1831.                         if (status_code == STATUS_PRINTER_IDLE or status_code == STATUS_PRINTER_OUT_OF_INK) and \
  1832.                             (agent_health == AGENT_HEALTH_OK or
  1833.                              (agent_health == AGENT_HEALTH_FAIR_MODERATE and agent_kind == AGENT_KIND_HEAD)) and \
  1834.                             agent_level_trigger >= AGENT_LEVEL_TRIGGER_MAY_BE_LOW:
  1835.  
  1836.                             query = 'agent_level_%s' % AGENT_levels.get(agent_level_trigger, 'unknown')
  1837.  
  1838.                             if tech_type in (TECH_TYPE_MONO_INK, TECH_TYPE_COLOR_INK):
  1839.                                 code = agent_type + STATUS_PRINTER_LOW_INK_BASE
  1840.                             else:
  1841.                                 code = agent_type + STATUS_PRINTER_LOW_TONER_BASE
  1842.  
  1843.                             self.dq['status-code'] = code
  1844.                             self.dq['status-desc'] = self.queryString(code)
  1845.  
  1846.                             self.dq['error-state'] = STATUS_TO_ERROR_STATE_MAP.get(code, ERROR_STATE_LOW_SUPPLIES)
  1847.                             self.error_code = code
  1848.                             self.sendEvent(self.error_code)
  1849.  
  1850.                             if agent_level_trigger in \
  1851.                                 (AGENT_LEVEL_TRIGGER_PROBABLY_OUT, AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT):
  1852.  
  1853.                                 query = 'agent_level_out'
  1854.                             else:
  1855.                                 query = 'agent_level_low'
  1856.  
  1857.                             agent_health_desc = self.queryString(query)
  1858.  
  1859.                             self.dq.update(
  1860.                             {
  1861.                                 'agent%d-kind' % aa :          agent_kind,
  1862.                                 'agent%d-type' % aa :          agent_type,
  1863.                                 'agent%d-known' % aa :         agent.get('known', False),
  1864.                                 'agent%d-sku' % aa :           mq_agent_sku,
  1865.                                 'agent%d-level' % aa :         agent_level,
  1866.                                 'agent%d-level-trigger' % aa : agent_level_trigger,
  1867.                                 'agent%d-ack' % aa :           agent.get('ack', False),
  1868.                                 'agent%d-hp-ink' % aa :        agent.get('hp-ink', False),
  1869.                                 'agent%d-health' % aa :        agent_health,
  1870.                                 'agent%d-dvc' % aa :           agent.get('dvc', 0),
  1871.                                 'agent%d-virgin' % aa :        agent.get('virgin', False),
  1872.                                 'agent%d-desc' % aa :          agent_desc,
  1873.                                 'agent%d-id' % aa :            agent.get('id', 0),
  1874.                                 'agent%d-health-desc' % aa :   agent_health_desc,
  1875.                             })
  1876.  
  1877.                         else:
  1878.                             query = 'agent_health_%s' % AGENT_healths.get(agent_health, AGENT_HEALTH_OK)
  1879.                             agent_health_desc = self.queryString(query)
  1880.  
  1881.                             self.dq.update(
  1882.                             {
  1883.                                 'agent%d-kind' % aa :          agent_kind,
  1884.                                 'agent%d-type' % aa :          agent_type,
  1885.                                 'agent%d-known' % aa :         False,
  1886.                                 'agent%d-sku' % aa :           mq_agent_sku,
  1887.                                 'agent%d-level' % aa :         agent_level,
  1888.                                 'agent%d-level-trigger' % aa : agent_level_trigger,
  1889.                                 'agent%d-ack' % aa :           False,
  1890.                                 'agent%d-hp-ink' % aa :        False,
  1891.                                 'agent%d-health' % aa :        agent_health,
  1892.                                 'agent%d-dvc' % aa :           0,
  1893.                                 'agent%d-virgin' % aa :        False,
  1894.                                 'agent%d-desc' % aa :          agent_desc,
  1895.                                 'agent%d-id' % aa :            0,
  1896.                                 'agent%d-health-desc' % aa :   agent_health_desc,
  1897.                             })
  1898.  
  1899.                         aa += 1
  1900.  
  1901.                     else:
  1902.                         log.debug("Not found: %d" % a)
  1903.  
  1904.                     a += 1
  1905.  
  1906.         else: # Create agent keys for not-found devices
  1907.  
  1908.             r_value = 0
  1909.             if r_type > 0 and self.r_values is not None:
  1910.                 r_value = self.r_values[0]
  1911.  
  1912.             # Make sure there is some valid agent data for this r_value
  1913.             # If not, fall back to r_value == 0
  1914.             if r_value > 0 and self.mq.get('r%d-agent1-kind', 0) == 0:
  1915.                 r_value = 0
  1916.  
  1917.             a = 1
  1918.             while True:
  1919.                 mq_agent_kind = self.mq.get('r%d-agent%d-kind' % (r_value, a), 0)
  1920.  
  1921.                 if mq_agent_kind == 0:
  1922.                     break
  1923.  
  1924.                 mq_agent_type = self.mq.get('r%d-agent%d-type' % (r_value, a), 0)
  1925.                 mq_agent_sku = self.mq.get('r%d-agent%d-sku' % (r_value, a), '')
  1926.                 query = 'agent_%s_%s' % (AGENT_types.get(mq_agent_type, 'unknown'),
  1927.                                          AGENT_kinds.get(mq_agent_kind, 'unknown'))
  1928.  
  1929.                 agent_desc = self.queryString(query)
  1930.  
  1931.                 self.dq.update(
  1932.                 {
  1933.                     'agent%d-kind' % a :          mq_agent_kind,
  1934.                     'agent%d-type' % a :          mq_agent_type,
  1935.                     'agent%d-known' % a :         False,
  1936.                     'agent%d-sku' % a :           mq_agent_sku,
  1937.                     'agent%d-level' % a :         0,
  1938.                     'agent%d-level-trigger' % a : AGENT_LEVEL_TRIGGER_ALMOST_DEFINITELY_OUT,
  1939.                     'agent%d-ack' % a :           False,
  1940.                     'agent%d-hp-ink' % a :        False,
  1941.                     'agent%d-health' % a :        AGENT_HEALTH_MISINSTALLED,
  1942.                     'agent%d-dvc' % a :           0,
  1943.                     'agent%d-virgin' % a :        False,
  1944.                     'agent%d-health-desc' % a :   self.queryString('agent_health_unknown'),
  1945.                     'agent%d-desc' % a :          agent_desc,
  1946.                     'agent%d-id' % a :            0,
  1947.                 })
  1948.  
  1949.                 a += 1
  1950.  
  1951.         for d in self.dq:
  1952.             self.__dict__[d.replace('-','_')] = self.dq[d]
  1953.  
  1954.         self.last_event = Event(self.device_uri, '', status_code, prop.username, 0, '', time.time())
  1955.         log.debug(self.dq)
  1956.  
  1957.  
  1958.     def isBusyOrInErrorState(self):
  1959.         try:
  1960.             self.queryDevice(quick=True)
  1961.         except Error:
  1962.             return True
  1963.         return self.error_state in (ERROR_STATE_ERROR, ERROR_STATE_BUSY)
  1964.  
  1965.  
  1966.     def isIdleAndNoError(self):
  1967.         try:
  1968.             self.queryDevice(quick=True)
  1969.         except Error:
  1970.             return False
  1971.         return self.error_state not in (ERROR_STATE_ERROR, ERROR_STATE_BUSY)
  1972.  
  1973.  
  1974.     def getPML(self, oid, desired_int_size=pml.INT_SIZE_INT): # oid => ( 'dotted oid value', pml type )
  1975.         channel_id = self.openPML()
  1976.  
  1977.         result_code, data, typ, pml_result_code = \
  1978.             hpmudext.get_pml(self.device_id, channel_id, pml.PMLToSNMP(oid[0]), oid[1])
  1979.  
  1980.         if pml_result_code > pml.ERROR_MAX_OK:
  1981.             log.debug("PML/SNMP GET %s failed (result code = 0x%x)" % (oid[0], pml_result_code))
  1982.             return pml_result_code, None
  1983.  
  1984.         converted_data = pml.ConvertFromPMLDataFormat(data, oid[1], desired_int_size)
  1985.  
  1986.         if log.is_debug():
  1987.             if oid[1] in (pml.TYPE_STRING, pml.TYPE_BINARY):
  1988.  
  1989.                 log.debug("PML/SNMP GET %s (result code = 0x%x) returned:" %
  1990.                     (oid[0], pml_result_code))
  1991.                 log.log_data(data)
  1992.             else:
  1993.                 log.debug("PML/SNMP GET %s (result code = 0x%x) returned: %s" %
  1994.                     (oid[0], pml_result_code, repr(converted_data)))
  1995.  
  1996.         return pml_result_code, converted_data
  1997.  
  1998.  
  1999.     def setPML(self, oid, value): # oid => ( 'dotted oid value', pml type )
  2000.         channel_id = self.openPML()
  2001.  
  2002.         value = pml.ConvertToPMLDataFormat(value, oid[1])
  2003.  
  2004.         result_code, pml_result_code = \
  2005.             hpmudext.set_pml(self.device_id, channel_id, pml.PMLToSNMP(oid[0]), oid[1], value)
  2006.  
  2007.         if log.is_debug():
  2008.             if oid[1] in (pml.TYPE_STRING, pml.TYPE_BINARY):
  2009.  
  2010.                 log.debug("PML/SNMP SET %s (result code = 0x%x) to:" %
  2011.                     (oid[0], pml_result_code))
  2012.                 log.log_data(value)
  2013.             else:
  2014.                 log.debug("PML/SNMP SET %s (result code = 0x%x) to: %s" %
  2015.                     (oid[0], pml_result_code, repr(value)))
  2016.  
  2017.         return pml_result_code
  2018.  
  2019.  
  2020.     def getDynamicCounter(self, counter, convert_to_int=True):
  2021.         dynamic_counters = self.mq.get('status-dynamic-counters', STATUS_DYNAMIC_COUNTERS_NONE)
  2022.         log.debug("Dynamic counters: %d" % dynamic_counters)
  2023.         if dynamic_counters != STATUS_DYNAMIC_COUNTERS_NONE:
  2024.  
  2025.             if dynamic_counters == STATUS_DYNAMIC_COUNTERS_LIDIL_0_5_4:
  2026.                 self.printData(ldl.buildResetPacket(), direct=True)
  2027.                 self.printData(ldl.buildDynamicCountersPacket(counter), direct=True)
  2028.             else:
  2029.                 self.printData(pcl.buildDynamicCounter(counter), direct=True)
  2030.  
  2031.             value, tries, times_seen, sleepy_time, max_tries = 0, 0, 0, 0.1, 5
  2032.             time.sleep(0.1)
  2033.  
  2034.             while True:
  2035.  
  2036.                 if self.callback:
  2037.                     self.callback()
  2038.  
  2039.                 sleepy_time += 0.1
  2040.                 tries += 1
  2041.  
  2042.                 time.sleep(sleepy_time)
  2043.  
  2044.                 self.getDeviceID()
  2045.  
  2046.                 if 'CTR' in self.deviceID and \
  2047.                     pat_dynamic_ctr.search(self.raw_deviceID) is not None:
  2048.                     dev_counter, value = parseDynamicCounter(self.deviceID['CTR'], convert_to_int)
  2049.  
  2050.                     if counter == dev_counter:
  2051.                         self.printData(pcl.buildDynamicCounter(0), direct=True)
  2052.                         # protect the value as a string during msg handling
  2053.                         if not convert_to_int:
  2054.                             value = '#' + value
  2055.                         return value
  2056.  
  2057.                 if tries > max_tries:
  2058.                     if dynamic_counters == STATUS_DYNAMIC_COUNTERS_LIDIL_0_5_4:
  2059.                         self.printData(ldl.buildResetPacket())
  2060.                         self.printData(ldl.buildDynamicCountersPacket(counter), direct=True)
  2061.                     else:
  2062.                         self.printData(pcl.buildDynamicCounter(0), direct=True)
  2063.  
  2064.                     return None
  2065.  
  2066.                 if dynamic_counters == STATUS_DYNAMIC_COUNTERS_LIDIL_0_5_4:
  2067.                     self.printData(ldl.buildResetPacket())
  2068.                     self.printData(ldl.buildDynamicCountersPacket(counter), direct=True)
  2069.                 else:
  2070.                     self.printData(pcl.buildDynamicCounter(counter), direct=True)
  2071.  
  2072.         else:
  2073.             raise Error(ERROR_DEVICE_DOES_NOT_SUPPORT_OPERATION)
  2074.  
  2075.  
  2076.     def readPrint(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  2077.         return self.__readChannel(self.openPrint, bytes_to_read, stream, timeout, allow_short_read)
  2078.  
  2079.     def readPCard(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  2080.         return self.__readChannel(self.openPCard, bytes_to_read, stream, timeout, allow_short_read)
  2081.  
  2082.     def readFax(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  2083.         return self.__readChannel(self.openFax, bytes_to_read, stream, timeout, allow_short_read)
  2084.  
  2085.     def readCfgUpload(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=False):
  2086.         return self.__readChannel(self.openCfgUpload, bytes_to_read, stream, timeout, allow_short_read)
  2087.  
  2088.     def readEWS(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=True):
  2089.         return self.__readChannel(self.openEWS, bytes_to_read, stream, timeout, allow_short_read)
  2090.  
  2091.     def readSoapFax(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=True):
  2092.         return self.__readChannel(self.openSoapFax, bytes_to_read, stream, timeout, allow_short_read)
  2093.  
  2094.     def readWifiConfig(self, bytes_to_read, stream=None, timeout=prop.read_timeout, allow_short_read=True):
  2095.         return self.__readChannel(self.openWifiConfig, bytes_to_read, stream, timeout, allow_short_read)
  2096.  
  2097.     def __readChannel(self, opener, bytes_to_read, stream=None,
  2098.                       timeout=prop.read_timeout, allow_short_read=False):
  2099.  
  2100.         channel_id = opener()
  2101.  
  2102.         log.debug("Reading channel %d (device-id=%d, bytes_to_read=%d, allow_short=%s, timeout=%d)..." %
  2103.             (channel_id, self.device_id, bytes_to_read, allow_short_read, timeout))
  2104.  
  2105.         num_bytes = 0
  2106.  
  2107.         if stream is None:
  2108.             buffer = ''
  2109.  
  2110.         while True:
  2111.             result_code, data = \
  2112.                 hpmudext.read_channel(self.device_id, channel_id, bytes_to_read, timeout)
  2113.  
  2114.             log.debug("Result code=%d" % result_code)
  2115.  
  2116.             l = len(data)
  2117.  
  2118.             if result_code == hpmudext.HPMUD_R_IO_TIMEOUT:
  2119.                 log.debug("I/O timeout")
  2120.                 break
  2121.  
  2122.             if result_code != hpmudext.HPMUD_R_OK:
  2123.                 log.error("Channel read error")
  2124.                 raise Error(ERROR_DEVICE_IO_ERROR)
  2125.  
  2126.             if not l:
  2127.                 log.debug("End of data")
  2128.                 break
  2129.  
  2130.             if stream is None:
  2131.                 buffer = ''.join([buffer, data])
  2132.             else:
  2133.                 stream.write(data)
  2134.  
  2135.             num_bytes += l
  2136.  
  2137.             if self.callback is not None:
  2138.                 self.callback()
  2139.  
  2140.             if num_bytes == bytes_to_read:
  2141.                 log.debug("Full read complete.")
  2142.                 break
  2143.  
  2144.             if allow_short_read and num_bytes < bytes_to_read:
  2145.                 log.debug("Allowed short read of %d of %d bytes complete." % (num_bytes, bytes_to_read))
  2146.                 break
  2147.  
  2148.         if stream is None:
  2149.             log.debug("Returned %d total bytes in buffer." % num_bytes)
  2150.             return buffer
  2151.         else:
  2152.             log.debug("Saved %d total bytes to stream." % num_bytes)
  2153.             return num_bytes
  2154.  
  2155.  
  2156.     def writePrint(self, data):
  2157.         return self.__writeChannel(self.openPrint, data)
  2158.  
  2159.     def writePCard(self, data):
  2160.         return self.__writeChannel(self.openPCard, data)
  2161.  
  2162.     def writeFax(self, data):
  2163.         return self.__writeChannel(self.openFax, data)
  2164.  
  2165.     def writeEWS(self, data):
  2166.         return self.__writeChannel(self.openEWS, data)
  2167.  
  2168.     def writeCfgDownload(self, data):
  2169.         return self.__writeChannel(self.openCfgDownload, data)
  2170.  
  2171.     def writeSoapFax(self, data):
  2172.         return self.__writeChannel(self.openSoapFax, data)
  2173.  
  2174.     def writeWifiConfig(self, data):
  2175.         return self.__writeChannel(self.openWifiConfig, data)
  2176.  
  2177.     def __writeChannel(self, opener, data):
  2178.         channel_id = opener()
  2179.         buffer, bytes_out, total_bytes_to_write = data, 0, len(data)
  2180.  
  2181.         log.debug("Writing %d bytes to channel %d (device-id=%d)..." % (total_bytes_to_write, channel_id, self.device_id))
  2182.  
  2183.         while len(buffer) > 0:
  2184.             result_code, bytes_written = \
  2185.                 hpmudext.write_channel(self.device_id, channel_id,
  2186.                     buffer[:prop.max_message_len])
  2187.  
  2188.             log.debug("Result code=%d" % result_code)
  2189.  
  2190.             if result_code != hpmudext.HPMUD_R_OK:
  2191.                 log.error("Channel write error")
  2192.                 raise Error(ERROR_DEVICE_IO_ERROR)
  2193.  
  2194.             buffer = buffer[prop.max_message_len:]
  2195.             bytes_out += bytes_written
  2196.  
  2197.             if self.callback is not None:
  2198.                 self.callback()
  2199.  
  2200.         if total_bytes_to_write != bytes_out:
  2201.             raise Error(ERROR_DEVICE_IO_ERROR)
  2202.  
  2203.         return bytes_out
  2204.  
  2205.  
  2206.     def writeEmbeddedPML(self, oid, value, style=1, direct=True):
  2207.         if style == 1:
  2208.             func = pcl.buildEmbeddedPML2
  2209.         else:
  2210.             func = pcl.buildEmbeddedPML
  2211.  
  2212.         data = func(pcl.buildPCLCmd('&', 'b', 'W',
  2213.                      pml.buildEmbeddedPMLSetPacket(oid[0],
  2214.                                                     value,
  2215.                                                     oid[1])))
  2216.  
  2217.         log.log_data(data)
  2218.  
  2219.         self.printData(data, direct=direct, raw=True)
  2220.  
  2221.  
  2222.     def printGzipFile(self, file_name, printer_name=None, direct=False, raw=True, remove=False):
  2223.         return self.printFile(file_name, printer_name, direct, raw, remove)
  2224.  
  2225.     def printParsedGzipPostscript(self, print_file, printer_name=None):
  2226.         # always: direct=False, raw=False, remove=True
  2227.         try:
  2228.             os.stat(print_file)
  2229.         except OSError:
  2230.             log.error("File not found: %s" % print_file)
  2231.             return
  2232.  
  2233.         temp_file_fd, temp_file_name = utils.make_temp_file()
  2234.         f = gzip.open(print_file, 'r')
  2235.  
  2236.         x = f.readline()
  2237.         while not x.startswith('%PY_BEGIN'):
  2238.             os.write(temp_file_fd, x)
  2239.             x = f.readline()
  2240.  
  2241.         sub_lines = []
  2242.         x = f.readline()
  2243.         while not x.startswith('%PY_END'):
  2244.             sub_lines.append(x)
  2245.             x = f.readline()
  2246.  
  2247.         SUBS = {'VERSION' : prop.version,
  2248.                  'MODEL'   : self.model_ui,
  2249.                  'URI'     : self.device_uri,
  2250.                  'BUS'     : self.bus,
  2251.                  'SERIAL'  : self.serial,
  2252.                  'IP'      : self.host,
  2253.                  'PORT'    : self.port,
  2254.                  'DEVNODE' : self.dev_file,
  2255.                  }
  2256.  
  2257.         if self.bus == 'net':
  2258.             SUBS['DEVNODE'] = 'n/a'
  2259.         else:
  2260.             SUBS['IP'] = 'n/a'
  2261.             SUBS['PORT'] = 'n/a'
  2262.  
  2263.         for s in sub_lines:
  2264.             os.write(temp_file_fd, s % SUBS)
  2265.  
  2266.         os.write(temp_file_fd, f.read())
  2267.         f.close()
  2268.         os.close(temp_file_fd)
  2269.  
  2270.         self.printFile(temp_file_name, printer_name, direct=False, raw=False, remove=True)
  2271.  
  2272.     def printFile(self, file_name, printer_name=None, direct=False, raw=True, remove=False):
  2273.         is_gzip = os.path.splitext(file_name)[-1].lower() == '.gz'
  2274.  
  2275.         if printer_name is None:
  2276.             printer_name = self.first_cups_printer
  2277.  
  2278.             if not printer_name:
  2279.                 raise Error(ERROR_NO_CUPS_QUEUE_FOUND_FOR_DEVICE)
  2280.  
  2281.         log.debug("Printing file '%s' to queue '%s' (gzip=%s, direct=%s, raw=%s, remove=%s)" %
  2282.                    (file_name, printer_name, is_gzip, direct, raw, remove))
  2283.  
  2284.         if direct: # implies raw==True
  2285.             if is_gzip:
  2286.                 self.writePrint(gzip.open(file_name, 'r').read())
  2287.             else:
  2288.                 self.writePrint(file(file_name, 'r').read())
  2289.  
  2290.         else:
  2291.             if not utils.which('lpr'):
  2292.                 lp_opt = ''
  2293.  
  2294.                 if raw:
  2295.                     lp_opt = '-oraw'
  2296.  
  2297.                 if is_gzip:
  2298.                     c = 'gunzip -c %s | lp -c -d%s %s' % (file_name, printer_name, lp_opt)
  2299.                 else:
  2300.                     c = 'lp -c -d%s %s %s' % (printer_name, lp_opt, file_name)
  2301.  
  2302.                 log.debug(c)
  2303.                 exit_code = os.system(c)
  2304.  
  2305.                 if exit_code != 0:
  2306.                     log.error("Print command failed with exit code %d!" % exit_code)
  2307.  
  2308.                 if remove:
  2309.                     os.remove(file_name)
  2310.  
  2311.             else:
  2312.                 raw_str, rem_str = '', ''
  2313.                 if raw: raw_str = '-o raw'
  2314.                 if remove: rem_str = '-r'
  2315.  
  2316.                 if is_gzip:
  2317.                     c = 'gunzip -c %s | lpr %s %s -P%s' % (file_name, raw_str, rem_str, printer_name)
  2318.                 else:
  2319.                     c = 'lpr -P%s %s %s %s' % (printer_name, raw_str, rem_str, file_name)
  2320.  
  2321.                 log.debug(c)
  2322.                 exit_code = os.system(c)
  2323.  
  2324.                 if exit_code != 0:
  2325.                     log.error("Print command failed with exit code %d!" % exit_code)
  2326.  
  2327.  
  2328.     def printTestPage(self, printer_name=None):
  2329.         return self.printParsedGzipPostscript(os.path.join( prop.home_dir, 'data',
  2330.                                               'ps', 'testpage.ps.gz' ), printer_name)
  2331.  
  2332.  
  2333.     def printData(self, data, printer_name=None, direct=True, raw=True):
  2334.         #log.log_data(data)
  2335.         #log.debug("printData(direct=%s, raw=%s)" % (direct, raw))
  2336.         if direct:
  2337.             self.writePrint(data)
  2338.         else:
  2339.             temp_file_fd, temp_file_name = utils.make_temp_file()
  2340.             os.write(temp_file_fd, data)
  2341.             os.close(temp_file_fd)
  2342.  
  2343.             self.printFile(temp_file_name, printer_name, False, raw, remove=True)
  2344.  
  2345.  
  2346.     def cancelJob(self, jobid):
  2347.         cups.cancelJob(jobid)
  2348.         self.error_code = STATUS_PRINTER_CANCELING
  2349.         self.sendEvent(self.error_code)
  2350.  
  2351.  
  2352.     def queryHistory(self):
  2353.         result = []
  2354.  
  2355.         if self.dbus_avail:
  2356.             try:
  2357.                 device_uri, history = self.service.GetHistory(self.device_uri)
  2358.             except dbus.exceptions.DBusException, e:
  2359.                 log.error("dbus call to GetHistory() failed.")
  2360.                 return []
  2361.  
  2362.             history.reverse()
  2363.  
  2364.             for h in history:
  2365.                 result.append(Event(*tuple(h)))
  2366.  
  2367.             try:
  2368.                 self.error_code = result[0].event_code
  2369.             except IndexError:
  2370.                 self.error_code = STATUS_UNKNOWN
  2371.  
  2372.             self.error_state = STATUS_TO_ERROR_STATE_MAP.get(self.error_code, ERROR_STATE_CLEAR)
  2373.  
  2374.         else:
  2375.             self.error_code = STATUS_UNKNOWN
  2376.             self.error_state = ERROR_STATE_CLEAR
  2377.  
  2378.         self.hist = result
  2379.         return result
  2380.  
  2381.  
  2382.  
  2383.     def getEWSUrl(self, url, stream):
  2384.         try:
  2385.             if self.is_local:
  2386.                 url2 = "%s&loc=%s" % (self.device_uri.replace('hpfax:', 'hp:'), url)
  2387.                 data = self
  2388.             else:
  2389.                 url2 = "http://%s%s" % (self.host, url)
  2390.                 if self.zc:
  2391.                     status, ip = hpmudext.get_zc_ip_address(self.zc)
  2392.                     if status == hpmudext.HPMUD_R_OK:
  2393.                         url2 = "http://%s%s" % (ip, url)
  2394.                 data = None
  2395.  
  2396.             log.debug("Opening: %s" % url2)
  2397.             opener = LocalOpener({})
  2398.             try:
  2399.                 f = opener.open(url2, data)
  2400.             except Error:
  2401.                 log.error("Status read failed: %s" % url2)
  2402.                 stream.seek(0)
  2403.                 stream.truncate()
  2404.             else:
  2405.                 try:
  2406.                     stream.write(f.read())
  2407.                 finally:
  2408.                     f.close()
  2409.  
  2410.         finally:
  2411.             self.closeEWS()
  2412.  
  2413.  
  2414.     def downloadFirmware(self, usb_bus_id=None, usb_device_id=None): # Note: IDs not currently used
  2415.         ok = False
  2416.         filename = os.path.join(prop.data_dir, "firmware", self.model.lower() + '.fw.gz')
  2417.         log.debug(filename)
  2418.  
  2419.         if os.path.exists(filename):
  2420.             log.debug("Downloading firmware file '%s'..." % filename)
  2421.  
  2422.             # Write to port directly (no MUD) so that HAL can enumerate the printer
  2423.             if 0: # this currently doesn't work because usblp is loaded...
  2424.             #if usb_bus_id is not None and usb_device_id is not None:
  2425.                 try:
  2426.                     p = "/dev/bus/usb/%s/%s" % (usb_bus_id, usb_device_id)
  2427.                     log.debug("Writing to %s..." % p)
  2428.                     f = os.open(p, os.O_RDWR)
  2429.                     x = gzip.open(filename).read()
  2430.                     os.write(f, x)
  2431.                     os.close(f)
  2432.                     ok = True
  2433.                     log.debug("OK")
  2434.                 except (OSError, IOError), e:
  2435.                     log.error("An error occured: %s" % e)
  2436.             else:
  2437.                 try:
  2438.                     self.openPrint()
  2439.                     bytes_written = self.writePrint(gzip.open(filename).read())
  2440.                     log.debug("%s bytes downloaded." % utils.commafy(bytes_written))
  2441.                     self.closePrint()
  2442.                     ok = True
  2443.                     log.debug("OK")
  2444.                 except Error, e:
  2445.                     log.error("An error occured: %s" % e.msg)
  2446.         else:
  2447.             log.error("Firmware file '%s' not found." % filename)
  2448.  
  2449.         return ok
  2450.  
  2451.  
  2452. # ********************************** Support classes/functions
  2453.  
  2454.  
  2455. class xStringIO(StringIO.StringIO):
  2456.     def makefile(self, x, y):
  2457.         return self
  2458.  
  2459. # URLs: hp:/usb/HP_LaserJet_3050?serial=00XXXXXXXXXX&loc=/hp/device/info_device_status.xml
  2460. class LocalOpener(urllib.URLopener):
  2461.     def open_hp(self, url, dev):
  2462.         log.debug("open_hp(%s)" % url)
  2463.  
  2464.         match_obj = http_pat_url.search(url)
  2465.         bus = match_obj.group(1) or ''
  2466.         model = match_obj.group(2) or ''
  2467.         serial = match_obj.group(3) or ''
  2468.         device = match_obj.group(4) or ''
  2469.         loc = match_obj.group(5) or ''
  2470.  
  2471.         dev.openEWS()
  2472.         dev.writeEWS("""GET %s HTTP/1.0\nContent-Length:0\nHost:localhost\nUser-Agent:hplip\n\n""" % loc)
  2473.  
  2474.         reply = xStringIO()
  2475.  
  2476.         while dev.readEWS(8192, reply, timeout=1):
  2477.             pass
  2478.  
  2479.         reply.seek(0)
  2480.         log.log_data(reply.getvalue())
  2481.  
  2482.         response = httplib.HTTPResponse(reply)
  2483.         response.begin()
  2484.  
  2485.         if response.status != httplib.OK:
  2486.             raise Error(ERROR_DEVICE_STATUS_NOT_AVAILABLE)
  2487.         else:
  2488.             return response.fp
  2489.  
  2490.  
  2491.